import * as isoly from "isoly" import { Authorization } from "../../Authorization" import { Reconciliation } from "../../Merchant/Reconciliation" import { Fee as SettlementFee } from "../../Settlement/Fee" import * as utilities from "../../utilities" import { Operation } from "../Operation" import { Network as NetworkFee } from "./Network" import { Transaction as TransactionFee } from "./Transaction" export type Fee = { [status in Operation]?: number } & { [country in isoly.CountryCode.Alpha2]?: TransactionFee } & { eea?: TransactionFee other: TransactionFee } export namespace Fee { export function is(value: any | Fee): value is Fee { return ( typeof value == "object" && Operation.types.every(v => value[v] == undefined || typeof value[v] == "number") && Object.keys(value) .filter(v => Operation.types.every(t => t != v)) .every(region => TransactionFee.is(value[region]) || region == undefined) && TransactionFee.is(value.other) ) } export function apply( operation: Operation, authorization: Authorization, reconciliation: Reconciliation, currency: isoly.Currency, gross: number, interchange: number, card: "debit" | "credit", rate: number, area: isoly.CountryCode.Alpha2 | undefined, precision = 4 ): SettlementFee { gross = Math.abs(gross) interchange = Math.abs(interchange) const scheme = authorization.card.scheme == "mastercard" ? "mastercard" : "visa" const fee = reconciliation.fees const feeModel = (area && fee[area]) ?? (area && isoly.CountryCode.Alpha2.isEEA(area) ? fee.eea ?? fee.other : fee.other) let network let intergiro if (operation == "capture") { const fixedFee = utilities.multiply(precision, fee["capture"] ?? 0, rate) intergiro = ((feeModel && TransactionFee.apply(scheme, card, "capture", feeModel, gross, currency, rate, fixedFee)) || 0) * -1 network = NetworkFee.apply(gross, rate, area, reconciliation.network?.[scheme]) * -1 interchange = interchange * -1 } else { gross = gross * -1 const captured = captureFees(authorization, precision) const refundIgFee = utilities.multiply(precision, fee[operation] ?? 0, rate) const captureIgFee = returnCaptureFee( gross, captured.totalAmount, reconciliation.costPlus ? captured.intergiroFee : captured.totalFee, precision, rate ) intergiro = utilities.subtract(precision, captureIgFee, refundIgFee) network = returnCaptureFee(gross, captured.totalAmount, captured.networkFee, precision, rate) } return reconciliation.costPlus ? { interchange, network, intergiro, total: utilities.add(precision, utilities.add(precision, intergiro, interchange), network), } : { interchange, network, intergiro: utilities.subtract(precision, utilities.subtract(precision, intergiro, network), interchange), total: intergiro, } } function returnCaptureFee( gross: number, captured: number, captureFee: number, precision: number, rate: number ): number { return captured != 0 ? utilities.multiply(precision, captureFee, gross / (captured * rate)) : 0 } function captureFees( authorization: Omit, precision = 4 ): { totalAmount: number intergiroFee: number networkFee: number totalFee: number } { let captured = 0 let intergiroFee = 0 let networkFee = 0 let totalFee = 0 for (const capture of authorization.capture ?? []) { captured += capture.settlement ? capture.amount : 0 intergiroFee += capture.settlement && SettlementFee.is(capture.settlement?.fee) ? capture.settlement.fee.intergiro : 0 networkFee += capture.settlement && SettlementFee.is(capture.settlement?.fee) ? capture.settlement.fee.network ?? 0 : 0 totalFee += capture.settlement && SettlementFee.is(capture.settlement?.fee) ? capture.settlement.fee.total ?? 0 : 0 } captured = utilities.round(captured, precision) intergiroFee = utilities.round(intergiroFee, precision) networkFee = utilities.round(networkFee, precision) totalFee = utilities.round(totalFee, precision) return { totalAmount: captured, intergiroFee, networkFee, totalFee } } export type Transaction = TransactionFee export namespace Transaction { export const is = TransactionFee.is export const isUnified = TransactionFee.isUnified export const apply = TransactionFee.apply } export type Network = NetworkFee export namespace Network { export const apply = NetworkFee.apply } }