Skip to content

Commit d414d19

Browse files
authored
Merge pull request #191 from topcoder-platform/dev
Support for 4 decimal places in markup calculation
2 parents 873033d + 2ad00d2 commit d414d19

11 files changed

Lines changed: 55 additions & 42 deletions

File tree

packages/finance-prisma-client/edge.js

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/finance-prisma-client/index.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/finance-prisma-client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "prisma-client-8e6584db420344c104dfb4ed4bc1d325cd5765efdf218c5bc263260e360dc646",
2+
"name": "prisma-client-1c9f61cf8e792f6948abaf67485be8959510b59ae7726d3b9d635f251ec9c9fb",
33
"main": "index.js",
44
"types": "index.d.ts",
55
"browser": "default.js",

packages/finance-prisma-client/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ model payment {
6060
release_date DateTime? @default(dbgenerated("(CURRENT_TIMESTAMP + '15 days'::interval)")) @db.Timestamp(6)
6161
payment_status payment_status?
6262
billing_account String @db.VarChar(80)
63-
challenge_markup Decimal? @db.Decimal(12, 2)
63+
challenge_markup Decimal? @db.Decimal(12, 4)
6464
challenge_fee Decimal? @db.Decimal(12, 2)
6565
payment_method payment_method? @relation(fields: [payment_method_id], references: [payment_method_id], onDelete: NoAction, onUpdate: NoAction)
6666
winnings winnings @relation(fields: [winnings_id], references: [winning_id], onDelete: NoAction, onUpdate: NoAction)

packages/finance-prisma-client/wasm.js

Lines changed: 2 additions & 3 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "payment" ALTER COLUMN "challenge_markup" TYPE DECIMAL(12,4);

prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ model payment {
5959
release_date DateTime? @default(dbgenerated("(CURRENT_TIMESTAMP + '15 days'::interval)")) @db.Timestamp(6)
6060
payment_status payment_status?
6161
billing_account String @db.VarChar(80)
62-
challenge_markup Decimal? @db.Decimal(12, 2)
62+
challenge_markup Decimal? @db.Decimal(12, 4)
6363
challenge_fee Decimal? @db.Decimal(12, 2)
6464
payment_method payment_method? @relation(fields: [payment_method_id], references: [payment_method_id], onDelete: NoAction, onUpdate: NoAction)
6565
winnings winnings @relation(fields: [winnings_id], references: [winning_id], onDelete: NoAction, onUpdate: NoAction)

src/api/winnings/winnings.service.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,10 @@ describe('WinningsService', () => {
212212
]);
213213
});
214214

215-
it('rounds engagement challenge markup before persisting the payment fee', async () => {
215+
it('preserves engagement challenge markup precision before calculating the payment fee', async () => {
216216
billingAccountsService.getBillingAccountById.mockResolvedValue({
217217
id: 123456,
218-
markup: 0.236,
218+
markup: 0.3989,
219219
});
220220

221221
await service.createWinningWithPayments(
@@ -243,12 +243,12 @@ describe('WinningsService', () => {
243243
const persistedPayment =
244244
tx.winnings.create.mock.calls[0][0].data.payment.create[0];
245245

246-
expect(Number(persistedPayment.challenge_markup)).toBe(0.24);
247-
expect(Number(persistedPayment.challenge_fee)).toBe(24);
246+
expect(Number(persistedPayment.challenge_markup)).toBe(0.3989);
247+
expect(Number(persistedPayment.challenge_fee)).toBe(39.89);
248248
expect(billingAccountsService.consumeAmounts).toHaveBeenCalledWith({
249249
consumes: [
250250
{
251-
amount: 124,
251+
amount: 139.89,
252252
billingAccountId: 123456,
253253
externalId: 'assignment-1',
254254
externalType: 'ENGAGEMENT',

src/api/winnings/winnings.service.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { resolveChallengeMemberPaymentAmount } from 'src/shared/payments/challen
4444

4545
const BUDGET_LEDGER_DECIMAL_PLACES = 4;
4646
const PAYMENT_DECIMAL_PLACES = 2;
47+
const PAYMENT_MARKUP_DECIMAL_PLACES = 4;
4748
export const CHALLENGE_BUDGET_SYNC_SKIP_ATTRIBUTE = 'skipChallengeBudgetSync';
4849

4950
interface EngagementBillingAccountConsume {
@@ -729,11 +730,25 @@ export class WinningsService {
729730
}
730731

731732
/**
732-
* Normalizes the engagement billing-account markup to the payment column
733-
* scale used by `payment.challenge_markup`.
733+
* Quantizes a payment markup to the persisted challenge-markup scale.
734+
*
735+
* Finance stores `payment.challenge_markup` at the same four-decimal scale as
736+
* billing-accounts-api-v6 markup values so fee calculations do not round the
737+
* rate to cents before multiplication.
738+
*
739+
* @param markup Decimal markup to normalize.
740+
* @returns JavaScript number rounded to the challenge-markup column scale.
741+
*/
742+
private toPaymentMarkup(markup: Prisma.Decimal): number {
743+
return this.toScaledAmount(markup, PAYMENT_MARKUP_DECIMAL_PLACES);
744+
}
745+
746+
/**
747+
* Normalizes the engagement billing-account markup for payment persistence
748+
* while preserving billing-account precision for downstream fee math.
734749
*
735750
* @param markup billing-account markup returned by billing-accounts-api-v6.
736-
* @returns Rounded markup suitable for persistence on payment rows.
751+
* @returns Four-decimal markup suitable for persistence on payment rows.
737752
* @throws InternalServerErrorException when the markup is not finite.
738753
*/
739754
private calculateEngagementChallengeMarkup(markup: number): number {
@@ -743,16 +758,15 @@ export class WinningsService {
743758
);
744759
}
745760

746-
return this.toPaymentAmount(new Prisma.Decimal(markup));
761+
return this.toPaymentMarkup(new Prisma.Decimal(markup));
747762
}
748763

749764
/**
750-
* Computes the persisted engagement challenge fee using the rounded payment
751-
* markup scale.
765+
* Computes the persisted engagement challenge fee using the normalized
766+
* billing-account markup.
752767
*
753768
* @param totalAmount payment detail total amount.
754-
* @param challengeMarkup rounded billing-account markup persisted on the
755-
* payment row.
769+
* @param challengeMarkup billing-account markup persisted on the payment row.
756770
* @param detailIndex zero-based detail index for error reporting.
757771
* @returns Payment-scale challenge fee.
758772
* @throws BadRequestException when the detail amount is invalid.
@@ -793,8 +807,7 @@ export class WinningsService {
793807
* Computes an engagement consume amount with decimal-safe arithmetic.
794808
*
795809
* @param totalAmount payment detail total amount.
796-
* @param challengeMarkup rounded billing-account markup persisted on the
797-
* payment row.
810+
* @param challengeMarkup billing-account markup persisted on the payment row.
798811
* @param detailIndex zero-based detail index for error reporting.
799812
* @returns Ledger-scale consume amount including markup.
800813
* @throws BadRequestException when the detail amount is invalid.
@@ -852,8 +865,8 @@ export class WinningsService {
852865
*
853866
* @param body incoming winning creation request.
854867
* @returns assignment id, trusted billing account id, and typed consume
855-
* requests to execute for non-TopGear billing accounts, plus the rounded
856-
* challenge markup persisted on the created payment rows.
868+
* requests to execute for non-TopGear billing accounts, plus the normalized
869+
* four-decimal challenge markup persisted on the created payment rows.
857870
* @throws BadRequestException when engagement payment input is invalid.
858871
* @throws InternalServerErrorException when billing-account metadata cannot
859872
* be normalized into a finite markup.

src/scripts/backfill-engagement-payment-challenge-markup-fees.sql

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
--
1414
-- Calculation:
1515
-- - payment.challenge_markup = billing account markup, rounded to the
16-
-- payment column scale.
16+
-- challenge-markup column scale.
1717
-- - payment.challenge_fee = payment.total_amount * payment.challenge_markup.
1818
-- - "billing-accounts"."ConsumedAmount".amount = payment.total_amount +
1919
-- payment.challenge_fee, rounded to the billing ledger scale.
@@ -75,10 +75,10 @@ WITH calculated AS (
7575
p.winnings_id,
7676
w.external_id AS "assignmentId",
7777
p.billing_account AS "billingAccount",
78-
ROUND(ba.markup::numeric, 2) AS "challengeMarkup",
78+
ROUND(ba.markup::numeric, 4) AS "challengeMarkup",
7979
CASE
8080
WHEN p.total_amount IS NULL THEN NULL
81-
ELSE ROUND(p.total_amount * ROUND(ba.markup::numeric, 2), 2)
81+
ELSE ROUND(p.total_amount * ROUND(ba.markup::numeric, 4), 2)
8282
END AS "challengeFee",
8383
p.challenge_markup AS "currentChallengeMarkup",
8484
p.challenge_fee AS "currentChallengeFee"
@@ -106,10 +106,10 @@ FROM candidates;
106106
WITH calculated AS (
107107
SELECT
108108
p.payment_id,
109-
ROUND(ba.markup::numeric, 2) AS "challengeMarkup",
109+
ROUND(ba.markup::numeric, 4) AS "challengeMarkup",
110110
CASE
111111
WHEN p.total_amount IS NULL THEN NULL
112-
ELSE ROUND(p.total_amount * ROUND(ba.markup::numeric, 2), 2)
112+
ELSE ROUND(p.total_amount * ROUND(ba.markup::numeric, 4), 2)
113113
END AS "challengeFee"
114114
FROM "finance"."payment" p
115115
INNER JOIN "finance"."winnings" w
@@ -167,7 +167,7 @@ WITH finance_payment_rows AS (
167167
ROUND(
168168
(
169169
p.total_amount
170-
+ ROUND(p.total_amount * ROUND(ba.markup::numeric, 2), 2)
170+
+ ROUND(p.total_amount * ROUND(ba.markup::numeric, 4), 2)
171171
)::numeric,
172172
4
173173
) AS "expectedConsumedAmount"
@@ -242,7 +242,7 @@ WITH finance_payment_rows AS (
242242
ROUND(
243243
(
244244
p.total_amount
245-
+ ROUND(p.total_amount * ROUND(ba.markup::numeric, 2), 2)
245+
+ ROUND(p.total_amount * ROUND(ba.markup::numeric, 4), 2)
246246
)::numeric,
247247
4
248248
) AS "expectedConsumedAmount"

0 commit comments

Comments
 (0)