hvp-shared 6.47.0 → 6.47.1
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.
|
@@ -128,8 +128,8 @@ export declare function calculateRecommendedPricePVP(params: {
|
|
|
128
128
|
unitPurchasePriceBI: number;
|
|
129
129
|
vatSalePercent: number;
|
|
130
130
|
}): number | null;
|
|
131
|
-
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) */
|
|
132
|
-
export declare const MIN_PRICE_COST_FACTOR =
|
|
131
|
+
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) — cost + 25% margin */
|
|
132
|
+
export declare const MIN_PRICE_COST_FACTOR = 1.25;
|
|
133
133
|
/** Cost-based multiplier for floor price (EXT_COST) */
|
|
134
134
|
export declare const MIN_PRICE_EXT_COST_FACTOR = 1;
|
|
135
135
|
/** Fraction of salePricePVP for recommended minimum price (COMP_SVC) */
|
|
@@ -218,9 +218,11 @@ function getDefaultPricePolicy(section, saleUnit, conversionFactor) {
|
|
|
218
218
|
// =============================================================================
|
|
219
219
|
// ROUNDING HELPER
|
|
220
220
|
// =============================================================================
|
|
221
|
-
/** Round to nearest multiple of 5 */
|
|
221
|
+
/** Round to nearest multiple of 5 (minimum 5 for positive values) */
|
|
222
222
|
function roundToNearest5(value) {
|
|
223
|
-
|
|
223
|
+
if (value <= 0)
|
|
224
|
+
return 0;
|
|
225
|
+
return Math.max(5, Math.round(value / 5) * 5);
|
|
224
226
|
}
|
|
225
227
|
/**
|
|
226
228
|
* Calculate the recommended price PVP (con IVA) for a catalog item.
|
|
@@ -243,8 +245,8 @@ function calculateRecommendedPricePVP(params) {
|
|
|
243
245
|
// =============================================================================
|
|
244
246
|
// FLOOR PRICE CALCULATION
|
|
245
247
|
// =============================================================================
|
|
246
|
-
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) */
|
|
247
|
-
exports.MIN_PRICE_COST_FACTOR =
|
|
248
|
+
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) — cost + 25% margin */
|
|
249
|
+
exports.MIN_PRICE_COST_FACTOR = 1.25;
|
|
248
250
|
/** Cost-based multiplier for floor price (EXT_COST) */
|
|
249
251
|
exports.MIN_PRICE_EXT_COST_FACTOR = 1.0;
|
|
250
252
|
/** Fraction of salePricePVP for recommended minimum price (COMP_SVC) */
|
|
@@ -319,17 +319,17 @@ describe('calculateFloorPrices', () => {
|
|
|
319
319
|
const defaults = { unitPurchasePriceBI: 100, vatSalePercent: 16, salePricePVP: 500 };
|
|
320
320
|
describe('cost-based policies (PHARM, PHARM_FRAC, COST_ML, COST)', () => {
|
|
321
321
|
const costPolicies = [pricing_constants_1.PricePolicy.PHARM, pricing_constants_1.PricePolicy.PHARM_FRAC, pricing_constants_1.PricePolicy.COST_ML, pricing_constants_1.PricePolicy.COST];
|
|
322
|
-
it.each(costPolicies)('%s: both = cost ×
|
|
323
|
-
// $100 *
|
|
322
|
+
it.each(costPolicies)('%s: both = cost × 1.25 × (1+VAT/100), round5', (policy) => {
|
|
323
|
+
// $100 * 1.25 * 1.16 = $145 → round5 = $145
|
|
324
324
|
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: policy });
|
|
325
|
-
expect(result.recommendedMinimumPrice).toBe(
|
|
326
|
-
expect(result.floorPrice).toBe(
|
|
325
|
+
expect(result.recommendedMinimumPrice).toBe(145);
|
|
326
|
+
expect(result.floorPrice).toBe(145);
|
|
327
327
|
});
|
|
328
328
|
it('should round to nearest 5', () => {
|
|
329
|
-
// $80 *
|
|
329
|
+
// $80 * 1.25 * 1.16 = $116 → round5 = $115
|
|
330
330
|
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.PHARM, unitPurchasePriceBI: 80 });
|
|
331
|
-
expect(result.recommendedMinimumPrice).toBe(
|
|
332
|
-
expect(result.floorPrice).toBe(
|
|
331
|
+
expect(result.recommendedMinimumPrice).toBe(115);
|
|
332
|
+
expect(result.floorPrice).toBe(115);
|
|
333
333
|
});
|
|
334
334
|
it('should return null when cost is 0', () => {
|
|
335
335
|
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.PHARM, unitPurchasePriceBI: 0 });
|
|
@@ -342,14 +342,20 @@ describe('calculateFloorPrices', () => {
|
|
|
342
342
|
expect(result.floorPrice).toBeNull();
|
|
343
343
|
});
|
|
344
344
|
it('should handle 0% VAT', () => {
|
|
345
|
-
// $100 *
|
|
345
|
+
// $100 * 1.25 * 1.0 = $125 → $125
|
|
346
346
|
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COST, vatSalePercent: 0 });
|
|
347
|
-
expect(result.recommendedMinimumPrice).toBe(
|
|
348
|
-
expect(result.floorPrice).toBe(
|
|
347
|
+
expect(result.recommendedMinimumPrice).toBe(125);
|
|
348
|
+
expect(result.floorPrice).toBe(125);
|
|
349
|
+
});
|
|
350
|
+
it('should never return less than 5 for positive cost', () => {
|
|
351
|
+
// $1 * 1.25 * 1.0 = $1.25 → round5 = 0, but min is 5
|
|
352
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.PHARM, unitPurchasePriceBI: 1, vatSalePercent: 0 });
|
|
353
|
+
expect(result.recommendedMinimumPrice).toBe(5);
|
|
354
|
+
expect(result.floorPrice).toBe(5);
|
|
349
355
|
});
|
|
350
356
|
});
|
|
351
357
|
describe('EXT_COST', () => {
|
|
352
|
-
it('both = cost × 1.0 × (1+VAT/100), round5', () => {
|
|
358
|
+
it('both = cost × 1.0 × (1+VAT/100), round5 (at-cost recovery)', () => {
|
|
353
359
|
// $100 * 1.0 * 1.16 = $116 → round5 = $115
|
|
354
360
|
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.EXT_COST });
|
|
355
361
|
expect(result.recommendedMinimumPrice).toBe(115);
|
|
@@ -366,6 +372,12 @@ describe('calculateFloorPrices', () => {
|
|
|
366
372
|
expect(result.recommendedMinimumPrice).toBe(230);
|
|
367
373
|
expect(result.floorPrice).toBe(230);
|
|
368
374
|
});
|
|
375
|
+
it('should never return less than 5 for positive cost', () => {
|
|
376
|
+
// $2 * 1.0 * 1.0 = $2 → round5 = 0, but min is 5
|
|
377
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.EXT_COST, unitPurchasePriceBI: 2, vatSalePercent: 0 });
|
|
378
|
+
expect(result.recommendedMinimumPrice).toBe(5);
|
|
379
|
+
expect(result.floorPrice).toBe(5);
|
|
380
|
+
});
|
|
369
381
|
});
|
|
370
382
|
describe('COMP_SVC', () => {
|
|
371
383
|
it('recommendedMinimumPrice = salePricePVP × 0.50, floorPrice = 0', () => {
|