fix: restore remaining content dropped by the dev merge (comprehensive audit)
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s

Systematic file-by-file audit of demo-backup against dev to find any
remaining instances of the same silent-drop pattern from the earlier
merge (git's 3-way auto-resolve keeping demo-backup's side wherever it
had independently touched nearby lines, even when dev's side was a
genuine, unrelated addition). Restored:

- clients.module.ts: missing ClientFamilyMemberChildDialogComponent
  registration (component existed but was never wired in)
- client-family-member-dialog: full children-management flow (checkbox,
  form array, child dialog integration, view/edit summary blocks)
- edit-client: FIR-exception flow for inaccessible old mobile numbers,
  and a hardened detectSensitiveFieldChanges() (null-guard, phone-digit
  normalization, dirty-checked comparisons to avoid false-positive
  Verify-Contact-Change prompts)
- shell.component.ts: withdrawal-review URL matcher extended to cover
  the Share Withdrawal Request review route
- fiu.component.html: AML alert status filter and monthly CTR reports
  table UI (backing logic already existed unused in the .ts)
- Shares module: Passbook tab (component existed but had no route or
  tab link), running-balance/resolution columns on the transactions
  tab, subscript-sizing fixes and a pill-style filter-bar redesign on
  Share Holders
- Savings/Share product accounting steps: Payment-Channel-to-Fund-
  Source mapping section, and Share Reference account restructuring
- pending-client-edits: email status badges + "View Email" button
  (dialog component existed but nothing on this list triggered it)

Everything else that still differs from dev was individually verified
as either demo-backup's own independent work (Investment/Loan
Origination/NPA/RBI-OSS modules, the Approval Center tab-nav redesign,
AML/compliance review features, bank-name rebrand in demo seed data)
or purely cosmetic formatting differences — left untouched.
This commit is contained in:
2026-08-06 16:35:52 +05:30
parent 9f9c9bfab6
commit 4281a596af
20 changed files with 845 additions and 88 deletions
@@ -115,6 +115,51 @@
</div>
</div>
}
<div class="spa-group">
<div class="spa-group__header">
<h4>Map Payment Types to Specific Funds</h4>
<button type="button" class="spa-add-btn" (click)="addPaymentFundSourceMapping()">+ Add</button>
</div>
<div class="spa-list" [formArrayName]="'paymentChannelToFundSourceMappings'">
@for (row of paymentChannelToFundSourceMappings.controls; track $index; let i = $index) {
<div class="spa-other-row-wrap">
<div class="spa-row spa-row--other" [formGroupName]="i">
<div class="spa-row__meta spa-row__meta--other">
<mat-form-field class="spa-row__other-field" appearance="outline" subscriptSizing="dynamic">
<mat-label>Payment Type</mat-label>
<mat-select formControlName="paymentTypeId">
@for (paymentType of paymentTypeOptions; track paymentType.id) {
<mat-option [value]="paymentType.id">{{ paymentType.name }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="spa-row__actions spa-row__actions--other">
<mat-form-field class="spa-row__other-field" appearance="outline" subscriptSizing="dynamic">
<mat-label>Fund Source</mat-label>
<mat-select formControlName="fundSourceAccountId">
@for (glAccount of fundSourceAccountOptions; track glAccount.id) {
<mat-option [value]="glAccount.id">
{{ '(' + glAccount.glCode + ') ' + glAccount.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
<button
type="button"
class="spa-remove-btn spa-remove-btn--side"
(click)="removePaymentFundSourceMapping(i)"
>
<i class="fas fa-times"></i>
</button>
</div>
}
</div>
</div>
}
</div>
</div>
@@ -50,6 +50,11 @@ type OtherGlMappingValue = {
glAccountId: number | null;
};
type PaymentFundSourceValue = {
paymentTypeId: number | null;
fundSourceAccountId: number | null;
};
@Component({
selector: 'mifosx-saving-product-accounting-step',
templateUrl: './saving-product-accounting-step.component.html',
@@ -78,6 +83,11 @@ export class SavingProductAccountingStepComponent implements OnInit {
expenseAccountOptions: GLAccount[] = [];
incomeAccountOptions: GLAccount[] = [];
assetAccountOptions: GLAccount[] = [];
paymentTypeOptions: any[] = [];
/** A payment-type Fund Source override can legitimately be a suspense/clearing Liability account
* (e.g. an existing "Sundry" account bridging to another module) rather than only a cash-like
* Asset account, so this field accepts either. */
fundSourceAccountOptions: GLAccount[] = [];
accountingSectionConfigs: AccountingSectionConfig[] = [];
constructor() {
@@ -98,6 +108,8 @@ export class SavingProductAccountingStepComponent implements OnInit {
this.liabilityAccountOptions = accountingMappingOptions.liabilityAccountOptions || [];
this.expenseAccountOptions = accountingMappingOptions.expenseAccountOptions || [];
this.incomeAccountOptions = accountingMappingOptions.incomeAccountOptions || [];
this.paymentTypeOptions = this.savingProductsTemplate?.paymentTypeOptions || [];
this.fundSourceAccountOptions = this.assetAccountOptions.concat(this.liabilityAccountOptions);
this.buildAccountingSectionConfigs();
this.savingProductAccountingForm.patchValue({
accountingRule: accountingRuleId
@@ -105,6 +117,7 @@ export class SavingProductAccountingStepComponent implements OnInit {
this.syncAccountingControls(accountingRuleId);
this.patchAccountingValues(mappings);
this.patchPaymentFundSourceMappings(this.savingProductsTemplate?.paymentChannelToFundSourceMappings || []);
this.setOverdraftControl();
this.setDormancyControl();
}
@@ -115,10 +128,48 @@ export class SavingProductAccountingStepComponent implements OnInit {
assetsOtherGlMappings: this.formBuilder.array([]),
liabilitiesOtherGlMappings: this.formBuilder.array([]),
expensesOtherGlMappings: this.formBuilder.array([]),
incomeOtherGlMappings: this.formBuilder.array([])
incomeOtherGlMappings: this.formBuilder.array([]),
paymentChannelToFundSourceMappings: this.formBuilder.array([])
});
}
get paymentChannelToFundSourceMappings(): UntypedFormArray {
return this.savingProductAccountingForm.get('paymentChannelToFundSourceMappings') as UntypedFormArray;
}
private createPaymentFundSourceGroup(value: Partial<PaymentFundSourceValue> = {}) {
return this.formBuilder.group({
paymentTypeId: [
value.paymentTypeId ?? this.paymentTypeOptions[0]?.id ?? null,
Validators.required
],
fundSourceAccountId: [
value.fundSourceAccountId ?? this.fundSourceAccountOptions[0]?.id ?? null,
Validators.required
]
});
}
private patchPaymentFundSourceMappings(mappings: any[]): void {
this.paymentChannelToFundSourceMappings.clear();
(mappings || []).forEach((mapping) => {
this.paymentChannelToFundSourceMappings.push(
this.createPaymentFundSourceGroup({
paymentTypeId: mapping.paymentType?.id,
fundSourceAccountId: mapping.fundSourceAccount?.id
})
);
});
}
addPaymentFundSourceMapping(): void {
this.paymentChannelToFundSourceMappings.push(this.createPaymentFundSourceGroup());
}
removePaymentFundSourceMapping(index: number): void {
this.paymentChannelToFundSourceMappings.removeAt(index);
}
private setConditionalControls() {
this.savingProductAccountingForm.get('accountingRule')?.valueChanges.subscribe((accountingRule: number) => {
this.syncAccountingControls(accountingRule);
@@ -74,6 +74,12 @@ export class ShareProductAccountingStepComponent implements OnInit {
liabilityAccountData: GLAccount[] = [];
incomeAccountData: GLAccount[] = [];
equityAccountData: GLAccount[] = [];
/** "Share Reference" is where a redemption's credit side lands pending settlement — some banks
* model that as a receivable-like Asset (e.g. "Cash Vault", this field's original default),
* others as a payable-like Liability suspense account (e.g. an existing "Sundry" account
* already used elsewhere as Shares Suspense). Both are valid conventions, so this field accepts
* either instead of Asset-only. */
referenceAccountData: GLAccount[] = [];
constructor() {
this.createShareProductAccountingForm();
@@ -85,6 +91,7 @@ export class ShareProductAccountingStepComponent implements OnInit {
this.liabilityAccountData = opts.liabilityAccountOptions || [];
this.incomeAccountData = opts.incomeAccountOptions || [];
this.equityAccountData = opts.equityAccountOptions || [];
this.referenceAccountData = this.assetAccountData.concat(this.liabilityAccountData);
this.buildAccountingSectionConfigs();
@@ -135,10 +142,10 @@ export class ShareProductAccountingStepComponent implements OnInit {
rows: [
{
key: 'shareReferenceId',
label: 'Share Reference (Cash Vault)',
label: 'Share Reference (Cash Vault or Suspense)',
inputLabel: 'Share reference',
controlName: 'shareReferenceId',
options: this.assetAccountData,
options: this.referenceAccountData,
required: true
}
],