vr-commons 1.0.139 → 1.0.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,10 +37,12 @@ export declare const DPP_OperationsUtil: {
37
37
  };
38
38
  /**
39
39
  * Generate installments for a hire purchase plan
40
+ * ✅ Updated to use unitPrice and create one installment at a time
40
41
  */
41
42
  generateInstallments(plan: DevicePaymentPlan, transaction?: Transaction): Promise<void>;
42
43
  /**
43
44
  * Format plan for operation response
45
+ * ✅ Updated to use unitPrice and totalAmount
44
46
  */
45
47
  formatPlanForOps(plan: DevicePaymentPlan | null): any;
46
48
  };
@@ -75,7 +75,7 @@ exports.DPP_OperationsUtil = {
75
75
  }
76
76
  // For now, require exact installment amount
77
77
  // Could be modified to allow overpayment later
78
- if (amount !== nextInstallment.amount) {
78
+ if (amount !== Number(nextInstallment.amount)) {
79
79
  return {
80
80
  valid: false,
81
81
  reason: `Payment amount must equal the next installment amount of ${nextInstallment.amount}`,
@@ -88,12 +88,13 @@ exports.DPP_OperationsUtil = {
88
88
  * Calculate new values after payment
89
89
  */
90
90
  calculatePaymentEffects(plan, amount) {
91
- const newPaidAmount = plan.paidAmount + amount;
92
- const newOutstandingAmount = Math.max(0, plan.outstandingAmount - amount);
91
+ // ✅ Use plan.totalAmount instead of pricingSnapshot.totalAmount
92
+ const totalAmount = Number(plan.totalAmount) || 0;
93
+ const newPaidAmount = Number(plan.paidAmount) + amount;
94
+ const newOutstandingAmount = Math.max(0, totalAmount - newPaidAmount);
93
95
  const wasCompleted = plan.status === "COMPLETED";
94
96
  const isNowCompleted = newOutstandingAmount <= 0;
95
- const totalAmount = plan.pricingSnapshot.totalAmount;
96
- const progress = (newPaidAmount / totalAmount) * 100;
97
+ const progress = totalAmount > 0 ? (newPaidAmount / totalAmount) * 100 : 0;
97
98
  return {
98
99
  newPaidAmount,
99
100
  newOutstandingAmount,
@@ -104,6 +105,7 @@ exports.DPP_OperationsUtil = {
104
105
  },
105
106
  /**
106
107
  * Generate installments for a hire purchase plan
108
+ * ✅ Updated to use unitPrice and create one installment at a time
107
109
  */
108
110
  async generateInstallments(plan, transaction) {
109
111
  const pricing = plan.pricingSnapshot;
@@ -112,7 +114,10 @@ exports.DPP_OperationsUtil = {
112
114
  }
113
115
  const InstallmentModel = vr_models_1.Installment;
114
116
  const installments = [];
115
- const dueDate = new Date(); // First installment due after creation
117
+ // ✅ Get device count from plan
118
+ const deviceCount = plan.devices?.length || 1;
119
+ const installmentAmount = Number(pricing.installmentAmount) * deviceCount;
120
+ const dueDate = new Date();
116
121
  if (pricing.installmentFrequency === "DAILY") {
117
122
  dueDate.setDate(dueDate.getDate() + 1);
118
123
  }
@@ -122,33 +127,29 @@ exports.DPP_OperationsUtil = {
122
127
  else if (pricing.installmentFrequency === "MONTHLY") {
123
128
  dueDate.setMonth(dueDate.getMonth() + 1);
124
129
  }
125
- for (let i = 1; i <= pricing.installmentCount; i++) {
126
- installments.push({
127
- devicePaymentPlanId: plan.id,
128
- installmentNumber: i,
129
- amount: Number(pricing.installmentAmount),
130
- dueDate: new Date(dueDate),
131
- status: "PENDING",
132
- isAutoGenerated: true,
133
- });
134
- // Calculate next due date
135
- if (pricing.installmentFrequency === "DAILY") {
136
- dueDate.setDate(dueDate.getDate() + 1);
137
- }
138
- else if (pricing.installmentFrequency === "WEEKLY") {
139
- dueDate.setDate(dueDate.getDate() + 7);
140
- }
141
- else if (pricing.installmentFrequency === "MONTHLY") {
142
- dueDate.setMonth(dueDate.getMonth() + 1);
143
- }
144
- }
145
- await InstallmentModel.bulkCreate(installments, { transaction });
130
+ // ✅ Create only the first installment (not all at once)
131
+ const firstInstallment = {
132
+ devicePaymentPlanId: plan.id,
133
+ installmentNumber: 1,
134
+ amount: installmentAmount,
135
+ paidAmount: 0.0,
136
+ dueDate: new Date(dueDate),
137
+ status: "PENDING",
138
+ isAutoGenerated: true,
139
+ metadata: {
140
+ totalInstallments: pricing.installmentCount,
141
+ remainingInstallments: pricing.installmentCount - 1,
142
+ createdAt: new Date().toISOString(),
143
+ },
144
+ };
145
+ await InstallmentModel.create(firstInstallment, { transaction });
146
146
  // Set the first installment as next due
147
- plan.nextInstallmentDueAt = installments[0]?.dueDate || null;
147
+ plan.nextInstallmentDueAt = firstInstallment.dueDate;
148
148
  await plan.save({ transaction });
149
149
  },
150
150
  /**
151
151
  * Format plan for operation response
152
+ * ✅ Updated to use unitPrice and totalAmount
152
153
  */
153
154
  formatPlanForOps(plan) {
154
155
  if (!plan)
@@ -158,6 +159,7 @@ exports.DPP_OperationsUtil = {
158
159
  id: plan.id,
159
160
  userId: plan.userId,
160
161
  pricingSnapshot: plan.pricingSnapshot,
162
+ totalAmount: plan.totalAmount, // ✅ Added
161
163
  paidAmount: plan.paidAmount,
162
164
  outstandingAmount: plan.outstandingAmount,
163
165
  lastPaymentAt: plan.lastPaymentAt,
@@ -170,21 +172,27 @@ exports.DPP_OperationsUtil = {
170
172
  user: plan.user || null,
171
173
  installments: plan.installments || [],
172
174
  };
173
- const totalAmount = planData.pricingSnapshot?.totalAmount || 0;
175
+ // ✅ Use plan.totalAmount instead of pricingSnapshot.totalAmount
176
+ const totalAmount = Number(planData.totalAmount) || 0;
174
177
  const hasInstallments = (planData.installments?.length ?? 0) > 0;
175
178
  return {
176
179
  id: planData.id,
177
180
  userId: planData.userId,
178
181
  pricingSnapshot: {
182
+ id: planData.pricingSnapshot?.id || null,
183
+ name: planData.pricingSnapshot?.name || null,
179
184
  type: planData.pricingSnapshot?.type || null,
180
- totalAmount: planData.pricingSnapshot?.totalAmount || 0,
185
+ unitPrice: planData.pricingSnapshot?.unitPrice || 0, // ✅ Changed from totalAmount
181
186
  downPayment: planData.pricingSnapshot?.downPayment || 0,
182
187
  installmentAmount: planData.pricingSnapshot?.installmentAmount || null,
183
188
  installmentFrequency: planData.pricingSnapshot?.installmentFrequency || null,
184
189
  installmentCount: planData.pricingSnapshot?.installmentCount || null,
185
190
  gracePeriodDays: planData.pricingSnapshot?.gracePeriodDays || 2,
186
191
  autoLockOnMiss: planData.pricingSnapshot?.autoLockOnMiss ?? true,
192
+ minOrderQuantity: planData.pricingSnapshot?.minOrderQuantity || 1,
193
+ maxOrderQuantity: planData.pricingSnapshot?.maxOrderQuantity || 1,
187
194
  },
195
+ totalAmount: totalAmount, // ✅ Added
188
196
  paidAmount: planData.paidAmount || 0,
189
197
  outstandingAmount: planData.outstandingAmount || 0,
190
198
  lastPaymentAt: planData.lastPaymentAt,
@@ -196,9 +204,9 @@ exports.DPP_OperationsUtil = {
196
204
  devices: planData.devices || [],
197
205
  user: planData.user || null,
198
206
  installments: planData.installments || [],
199
- progress: totalAmount > 0 ? (plan.paidAmount / totalAmount) * 100 : 0,
200
- canEdit: plan.paidAmount === 0,
201
- canDelete: plan.paidAmount === 0,
207
+ progress: totalAmount > 0 ? (Number(plan.paidAmount) / totalAmount) * 100 : 0,
208
+ canEdit: Number(plan.paidAmount) === 0,
209
+ canDelete: Number(plan.paidAmount) === 0,
202
210
  isOverdue: false,
203
211
  hasInstallments,
204
212
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vr-commons",
3
- "version": "1.0.139",
3
+ "version": "1.0.140",
4
4
  "description": "Shared functions package",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",