Fix: Product ledger was not totalling. This is because for some reason, pydantic was sending the data as string when the field was nullable
207 lines
8.7 KiB
HTML
207 lines
8.7 KiB
HTML
<mat-card>
|
|
<mat-card-header>
|
|
<mat-card-title-group>
|
|
<mat-card-title>Purchase</mat-card-title>
|
|
<mat-icon
|
|
matSuffix
|
|
(click)="voucher.isStarred = !voucher.isStarred"
|
|
class="pointer"
|
|
[class.gold]="voucher.isStarred"
|
|
>
|
|
{{ voucher.isStarred ? 'star' : 'star_border' }}
|
|
</mat-icon>
|
|
</mat-card-title-group>
|
|
</mat-card-header>
|
|
<mat-card-content>
|
|
<form [formGroup]="form" class="flex flex-col">
|
|
<div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
|
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
|
<mat-label>Date</mat-label>
|
|
<input
|
|
matInput
|
|
[matDatepicker]="date"
|
|
formControlName="date"
|
|
autocomplete="off"
|
|
#dateElement
|
|
(focus)="dateElement.select()"
|
|
/>
|
|
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
|
<mat-datepicker #date></mat-datepicker>
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-2/5 mr-5">
|
|
<mat-label>Account</mat-label>
|
|
<input
|
|
type="text"
|
|
matInput
|
|
#accountElement
|
|
[matAutocomplete]="autoA"
|
|
formControlName="account"
|
|
autocomplete="off"
|
|
/>
|
|
<mat-hint *ngIf="accBal">
|
|
Balance as on Date: <strong>{{ accBal.date | currency: 'INR' | accounting }}</strong> / Final balance:
|
|
<strong>{{ accBal.total | currency: 'INR' | accounting }}</strong>
|
|
</mat-hint>
|
|
<mat-autocomplete
|
|
#autoA="matAutocomplete"
|
|
autoActiveFirstOption
|
|
[displayWith]="displayFn"
|
|
(optionSelected)="accountSelected($event)"
|
|
>
|
|
<mat-option *ngFor="let account of accounts | async" [value]="account">{{ account.name }}</mat-option>
|
|
</mat-autocomplete>
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-1/5">
|
|
<mat-label>Amount</mat-label>
|
|
<input type="text" matInput formControlName="amount" />
|
|
<span matTextPrefix>₹ </span>
|
|
</mat-form-field>
|
|
</div>
|
|
|
|
<div formGroupName="addRow" class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
|
|
<mat-form-field class="flex-auto basis-1/2 mr-5">
|
|
<mat-label>Product</mat-label>
|
|
<input
|
|
type="text"
|
|
matInput
|
|
#productElement
|
|
[matAutocomplete]="autoP"
|
|
formControlName="product"
|
|
autocomplete="off"
|
|
/>
|
|
<mat-autocomplete
|
|
#autoP="matAutocomplete"
|
|
autoActiveFirstOption
|
|
[displayWith]="displayFn"
|
|
(optionSelected)="productSelected($event)"
|
|
>
|
|
<mat-option *ngFor="let product of products | async" [value]="product">{{ product.name }}</mat-option>
|
|
</mat-autocomplete>
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-1/10 mr-5">
|
|
<mat-label>Quantity</mat-label>
|
|
<input type="text" matInput formControlName="quantity" autocomplete="off" />
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-1/10 mr-5">
|
|
<mat-label>Price</mat-label>
|
|
<input type="text" matInput formControlName="price" autocomplete="off" />
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-1/10 mr-5">
|
|
<mat-label>Tax</mat-label>
|
|
<input type="text" matInput formControlName="tax" autocomplete="off" />
|
|
</mat-form-field>
|
|
<mat-form-field class="flex-auto basis-1/10 mr-5">
|
|
<mat-label>Discount</mat-label>
|
|
<input type="text" matInput formControlName="discount" autocomplete="off" />
|
|
</mat-form-field>
|
|
|
|
<button mat-raised-button color="primary" (click)="addRow()" class="flex-auto basis-1/10">Add</button>
|
|
</div>
|
|
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
|
|
<!-- Product Column -->
|
|
<ng-container matColumnDef="product">
|
|
<mat-header-cell *matHeaderCellDef>Product</mat-header-cell>
|
|
<mat-cell *matCellDef="let row">{{ row.batch.sku.name }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Quantity Column -->
|
|
<ng-container matColumnDef="quantity">
|
|
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="right">{{ row.quantity | number: '1.2-2' }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Rate Column -->
|
|
<ng-container matColumnDef="rate">
|
|
<mat-header-cell *matHeaderCellDef class="right">Rate</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="right">{{ row.rate | currency: 'INR' }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Tax Column -->
|
|
<ng-container matColumnDef="tax">
|
|
<mat-header-cell *matHeaderCellDef class="right">Tax</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="right">{{ row.tax | percent: '1.2-2' }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Discount Column -->
|
|
<ng-container matColumnDef="discount">
|
|
<mat-header-cell *matHeaderCellDef class="right">Discount</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="right">{{ row.discount | percent: '1.2-2' }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Amount Column -->
|
|
<ng-container matColumnDef="amount">
|
|
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
|
|
</ng-container>
|
|
|
|
<!-- Action Column -->
|
|
<ng-container matColumnDef="action">
|
|
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
|
|
<mat-cell *matCellDef="let row" class="center">
|
|
<button mat-icon-button tabindex="-1" (click)="editRow(row)">
|
|
<mat-icon>edit</mat-icon>
|
|
</button>
|
|
<button mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
|
|
<mat-icon>delete</mat-icon>
|
|
</button>
|
|
</mat-cell>
|
|
</ng-container>
|
|
|
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
|
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
|
</mat-table>
|
|
<mat-form-field>
|
|
<mat-label>Narration</mat-label>
|
|
<textarea matInput matAutosizeMinRows="5" formControlName="narration"></textarea>
|
|
</mat-form-field>
|
|
<div class="flex flex-row justify-center items-stretch mr-5">
|
|
<div class="img-container" class="flex-auto mr-5 basis-1/5" *ngFor="let item of voucher.files">
|
|
<img [src]="item.thumbnail" (click)="zoomImage(item)" />
|
|
<button mat-icon-button class="overlay" (click)="deleteImage(item)">
|
|
<mat-icon>delete</mat-icon>
|
|
</button>
|
|
</div>
|
|
<div class="img-container" class="flex flex-auto basis-1/5">
|
|
<label ng-href for="fileUp">
|
|
<img
|
|
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTUwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjE1MCIgZmlsbD0iI2VlZSIvPjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjUwIiB5PSI3NSIgc3R5bGU9ImZpbGw6I2FhYTtmb250LXdlaWdodDpib2xkO2ZvbnQtc2l6ZToxMDBweDtmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjtkb21pbmFudC1iYXNlbGluZTpjZW50cmFsIj4rPC90ZXh0Pjwvc3ZnPg=="
|
|
/>
|
|
</label>
|
|
<input
|
|
type="file"
|
|
id="fileUp"
|
|
multiple
|
|
accept="image/*"
|
|
style="display: none"
|
|
(change)="image.detectFiles($event, voucher)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</mat-card-content>
|
|
<mat-card-actions>
|
|
<button mat-raised-button color="primary" (click)="save()" [disabled]="!canSave()" class="mr-5">
|
|
{{ voucher.id ? 'Update' : 'Save' }}
|
|
</button>
|
|
<button
|
|
mat-raised-button
|
|
(click)="post()"
|
|
*ngIf="voucher.id"
|
|
[disabled]="voucher.posted || !auth.allowed('post-vouchers')"
|
|
class="mr-5"
|
|
>
|
|
{{ voucher.posted ? 'Posted' : 'Post' }}
|
|
</button>
|
|
<button mat-raised-button color="warn" (click)="confirmDelete()" *ngIf="voucher.id" [disabled]="!canSave()">
|
|
Delete
|
|
</button>
|
|
<span class="fill-remaining-space"></span>
|
|
<span *ngIf="voucher.id" class="flex">
|
|
Created on <strong>{{ voucher.creationDate | localTime }}</strong
|
|
> and Last Edited on <strong>{{ voucher.lastEditDate | localTime }}</strong
|
|
> by <strong>{{ voucher.user.name }}</strong
|
|
>. {{ voucher.poster ? 'Posted by ' + voucher.poster : '' }}
|
|
</span>
|
|
</mat-card-actions>
|
|
</mat-card>
|