feat(savings,shares): bidirectional savings/share account linking, new Migrate Cash Denomination screen
- Savings account creation shows a required "Default Share Account" picker once Share Linking is enabled, populated from the client's active share accounts; submits shareAccountId alongside it. - Fixes a real data-loss bug on Share Account creation: the Charges step re-seeded its table from the product's default charges on every ngOnChanges firing (e.g. stepping back to Details and forward again), silently discarding a charge the clerk had already added, edited, or removed - a pristine guard existed for exactly this but wasn't checked in ngOnChanges. Now it is. - Removes the hard "required" on Share Account creation's Default Savings Account field, matching the backend now accepting a share account with no linked savings account. - New /accounting/migrate-cash-denomination screen: counts a branch's opening cash into notes and coins, checks it against (or defines, if unset) the Cash GL account's balance, and opens the branch's first business day with that same count - the vault-side counterpart to Migrate Opening Balances, kept under Accounting rather than Branch Ops/Cashier so it isn't reachable by mistake. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+8
-1
@@ -111,7 +111,14 @@ export class SharesAccountChargesStepComponent implements OnInit, OnChanges {
|
||||
ngOnChanges() {
|
||||
if (this.sharesAccountProductTemplate) {
|
||||
this.chargeData = this.sharesAccountTemplate.chargeOptions;
|
||||
this.chargesDataSource = this.sharesAccountProductTemplate.charges;
|
||||
// Re-seeding from the product's own charges is only correct the first time this template
|
||||
// arrives (picking the product). The productId control's valueChanges fires again on any
|
||||
// later patchValue with the same id - stepping back to Details and forward again, for
|
||||
// instance - and re-emits this same template; without this guard, that silently wipes
|
||||
// whatever the user had already added, edited, or removed on this step.
|
||||
if (this.pristine) {
|
||||
this.chargesDataSource = this.sharesAccountProductTemplate.charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-8
@@ -30,20 +30,13 @@
|
||||
<span class="flex-48">{{ calculateCurrenValue() | currency: currency.code : 'symbol-narrow' : '1.2-2' }}</span>
|
||||
}
|
||||
|
||||
<!-- No "None" option: the server rejects a share account without a linked savings account, and
|
||||
offering the choice only produced a failure after the whole stepper was filled in. The link
|
||||
is also where an over-payment at the counter is credited back to the member. -->
|
||||
<mat-form-field class="flex-48">
|
||||
<mat-label>{{ 'labels.inputs.Default Savings Account' | translate }}</mat-label>
|
||||
<mat-select formControlName="savingsAccountId" required>
|
||||
<mat-select formControlName="savingsAccountId">
|
||||
@for (account of savingsAccountsData; track account) {
|
||||
<mat-option [value]="account.id"> {{ account.accountNo }} - {{ account.savingsProductName }} </mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Default Savings Account' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
@if (savingsAccountsData?.length === 0) {
|
||||
<p class="sats-field-note flex-98">
|
||||
|
||||
+1
-11
@@ -128,17 +128,7 @@ export class SharesAccountTermsStepComponent implements OnChanges, OnInit {
|
||||
],
|
||||
unitPrice: [{ value: '', disabled: true }],
|
||||
currencyMultiple: [{ value: '', disabled: true }],
|
||||
// Required to match the server, which has always rejected a share account without a linked
|
||||
// savings account. The form allowed one through, so the failure surfaced as a validation
|
||||
// error on submit after the whole stepper had been filled in.
|
||||
//
|
||||
// It also gives an over-payment somewhere to go: a member who hands over more cash than the
|
||||
// application costs has the difference credited to this account, rather than being left in a
|
||||
// suspense GL that nobody can attribute back to them.
|
||||
savingsAccountId: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
savingsAccountId: [''],
|
||||
minimumActivePeriod: [''],
|
||||
minimumActivePeriodFrequencyType: [''],
|
||||
lockinPeriodFrequency: [''],
|
||||
|
||||
Reference in New Issue
Block a user