Skip to content

Commit bc220ad

Browse files
authored
Merge branch 'dev' into angular20
2 parents 7fd1486 + 923f792 commit bc220ad

File tree

9 files changed

+66
-7
lines changed

9 files changed

+66
-7
lines changed

src/app/clients/clients-view/custom-dialogs/capture-image-dialog/capture-image-dialog.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="layout-column gap-2px">
22
<h1 mat-dialog-title align="center">{{ 'labels.heading.Capture Client Image' | translate }}</h1>
33

4-
<video #video width="540" height="480" autoplay></video>
4+
<video #video class="capture-video" autoplay></video>
55

66
<!-- Using a class will break renderer changes -->
77
<canvas #canvas [ngStyle]="{ display: 'none' }"></canvas>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@use '../../../../../assets/styles/colours' as colors;
2+
3+
.capture-video {
4+
width: 100%;
5+
max-width: 640px;
6+
height: auto;
7+
object-fit: contain;
8+
border-radius: 4px;
9+
background-color: colors.$black;
10+
}

src/app/clients/clients-view/custom-dialogs/capture-image-dialog/capture-image-dialog.component.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,13 @@ export class CaptureImageDialogComponent implements AfterViewInit, OnDestroy {
5454
*/
5555
startCamera() {
5656
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
57+
const videoConstraints: MediaTrackConstraints = {
58+
width: { ideal: 640 },
59+
height: { ideal: 480 },
60+
facingMode: 'user'
61+
};
5762
navigator.mediaDevices
58-
.getUserMedia({ video: true })
63+
.getUserMedia({ video: videoConstraints })
5964
.then((stream: MediaStream) => {
6065
this.renderer.setProperty(this.video.nativeElement, 'srcObject', stream);
6166
this.video.nativeElement.play();
@@ -95,13 +100,26 @@ export class CaptureImageDialogComponent implements AfterViewInit, OnDestroy {
95100

96101
/**
97102
* Captures the image by drawing video state on canvas, then converts canvas state to data URL.
103+
* Uses actual video dimensions to prevent aspect ratio distortion.
98104
* See https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL for details.
99105
*/
100106
capture() {
101107
this.isCaptured = true;
102108
this.video.nativeElement.pause();
103-
this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, 150, 150);
104-
this.clientImageDataURL = this.canvas.nativeElement.toDataURL();
109+
110+
// Get actual video stream dimensions to preserve aspect ratio
111+
const videoWidth = this.video.nativeElement.videoWidth;
112+
const videoHeight = this.video.nativeElement.videoHeight;
113+
114+
// Set canvas dimensions to match video stream
115+
this.canvas.nativeElement.width = videoWidth;
116+
this.canvas.nativeElement.height = videoHeight;
117+
118+
// Draw the video frame at full resolution without distortion
119+
this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, videoWidth, videoHeight);
120+
121+
// Convert to data URL with JPEG format for smaller file size
122+
this.clientImageDataURL = this.canvas.nativeElement.toDataURL('image/jpeg', 0.9);
105123
}
106124

107125
/**

src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
255255
this.loansAccountTermsForm.addControl('enableDownPayment', new UntypedFormControl(enableDownPayment));
256256
}
257257

258+
if (this.isFullTermTrancheEditable()) {
259+
const allowFullTermForTranche =
260+
this.loansAccountTermsData.allowFullTermForTranche ?? this.loanProduct?.allowFullTermForTranche ?? false;
261+
this.loansAccountTermsForm.patchValue({ allowFullTermForTranche });
262+
}
263+
258264
const allowAttributeOverrides = this.loansAccountTermsData.product.allowAttributeOverrides;
259265
if (!allowAttributeOverrides.repaymentEvery) {
260266
this.loansAccountTermsForm.controls.repaymentEvery.disable();
@@ -517,7 +523,8 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
517523
multiDisburseLoan: [false],
518524
interestRateFrequencyType: [''],
519525
balloonRepaymentAmount: [''],
520-
interestRecognitionOnDisbursementDate: [false]
526+
interestRecognitionOnDisbursementDate: [false],
527+
allowFullTermForTranche: [false]
521528
});
522529
}
523530

@@ -699,4 +706,12 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
699706
collateral: this.collateralDataSource
700707
};
701708
}
709+
710+
/**
711+
* Check if full term tranche option should be editable at loan level.
712+
* Only available if the loan product has it enabled and is PROGRESSIVE schedule type.
713+
*/
714+
isFullTermTrancheEditable(): boolean {
715+
return this.isProgressive && this.loanProduct?.allowFullTermForTranche === true;
716+
}
702717
}

src/app/loans/loans-view/loan-tranche-details/loan-tranche-details.component.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
<span class="flex-60">{{ loanDetails.maxOutstandingLoanBalance | formatNumber }}</span>
55
</div>
66

7+
<div class="flex-fill" *ngIf="loanDetails.allowFullTermForTranche">
8+
<span class="flex-40">{{ 'labels.inputs.Allow full term for each tranche' | translate }}:</span>
9+
<span class="flex-60">{{ loanDetails.allowFullTermForTranche | yesNo }}</span>
10+
</div>
11+
712
<h3>{{ 'labels.heading.Loan Tranche Details' | translate }}</h3>
813

914
<div class="layout-row margin-t layout-xs-column layout-align-end gap-2percent">

src/app/loans/loans-view/loan-tranche-details/loan-tranche-details.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
import { MatTooltip } from '@angular/material/tooltip';
2828
import { DateFormatPipe } from '../../../pipes/date-format.pipe';
2929
import { FormatNumberPipe } from '../../../pipes/format-number.pipe';
30+
import { YesnoPipe } from '../../../pipes/yesno.pipe';
3031
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
3132

3233
@Component({
@@ -49,7 +50,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
4950
MatRowDef,
5051
MatRow,
5152
DateFormatPipe,
52-
FormatNumberPipe
53+
FormatNumberPipe,
54+
YesnoPipe
5355
]
5456
})
5557
export class LoanTrancheDetailsComponent implements OnInit {

src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
146146
multiDisburseLoan: this.loanProductsTemplate.multiDisburseLoan,
147147
maxTrancheCount: this.loanProductsTemplate.maxTrancheCount,
148148
outstandingLoanBalance: this.loanProductsTemplate.outstandingLoanBalance,
149+
allowFullTermForTranche: this.loanProductsTemplate.allowFullTermForTranche,
149150
enableDownPayment: this.loanProductsTemplate.enableDownPayment,
150151
enableInstallmentLevelDelinquency: this.loanProductsTemplate.enableInstallmentLevelDelinquency,
151152
loanScheduleType: this.loanProductsTemplate.loanScheduleType.code,
@@ -314,6 +315,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
314315
isInterestRecalculationEnabled: [false],
315316
holdGuaranteeFunds: [false],
316317
multiDisburseLoan: [false],
318+
allowFullTermForTranche: [false],
317319
allowAttributeConfiguration: [true],
318320
allowPartialPeriodInterestCalculation: [false],
319321
allowAttributeOverrides: this.formBuilder.group({
@@ -553,7 +555,10 @@ export class LoanProductSettingsStepComponent implements OnInit {
553555
} else {
554556
this.loanProductSettingsForm.removeControl('maxTrancheCount');
555557
this.loanProductSettingsForm.removeControl('outstandingLoanBalance');
556-
this.loanProductSettingsForm.patchValue({ disallowExpectedDisbursements: false });
558+
this.loanProductSettingsForm.patchValue({
559+
disallowExpectedDisbursements: false,
560+
allowFullTermForTranche: false
561+
});
557562
}
558563
});
559564

@@ -647,6 +652,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
647652
this.advancedTransactionProcessingStrategyDisabled = false;
648653
this.isAdvancedTransactionProcessingStrategy = false;
649654
this.loanProductSettingsForm.removeControl('chargeOffBehaviour');
655+
this.loanProductSettingsForm.patchValue({ allowFullTermForTranche: false });
650656
} else {
651657
// Only Advanced Payment Allocation Strategy
652658
this.transactionProcessingStrategyDataBase.some((cn: CodeName) => {

src/app/products/loan-products/models/loan-product.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface LoanProduct {
9797
creditAllocationAllocationTypes: OptionData[];
9898
multiDisburseLoan: boolean;
9999
maxTrancheCount: number;
100+
allowFullTermForTranche: boolean;
100101
disallowExpectedDisbursements: boolean;
101102
allowApprovedDisbursedAmountsOverApplied: boolean;
102103
overAppliedNumber: number;

src/assets/translations/en-US.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,7 @@
15991599
"Enable Dormancy Tracking": "Enable Dormancy Tracking",
16001600
"Enable Down Payment": "Enable Down Payment",
16011601
"Enable Multiple Disbursals": "Enable Multiple Disbursals",
1602+
"Allow full term for each tranche": "Allow full term for each tranche",
16021603
"Enabled": "Enabled",
16031604
"End Date": "End Date",
16041605
"End Point": "End Point",
@@ -3566,6 +3567,7 @@
35663567
"Keyboard Shortcuts": "Keyboard Shortcuts",
35673568
"Leave this checkbox checked if the loan has Down Payment": "Leave this checkbox checked if the loan has Down Payment, A Down Payment is a sum a buyer pays upfront when purchasing a good. It represents a percentage of the total purchase price, and the balance is usually financed",
35683569
"Leave this checkbox unchecked": "Leave this checkbox unchecked if the loan is a single disburse loan. Check this checkbox if the loan is a multi disburse loan. See additional fields for additional information required for this type of loan.",
3570+
"Allow full term length for each tranche disbursement": "When enabled, each tranche disbursement will follow the full loan term schedule instead of fitting within the remaining term. Only available for PROGRESSIVE loan schedule type.",
35693571
"Loan Account": "Loan Account",
35703572
"Loan Product can be used to apply for Topup Loans": "If selected, the Loan Product can be used to apply for Top Up Loans.",
35713573
"Loan products may be assigned": "Loan products may be assigned to a fund set up by your financial institution. If available, the fund field can be used for tracking and reporting on groups of loans.",

0 commit comments

Comments
 (0)