import * as isoly from "isoly" import * as authly from "authly" import * as base from "@payfunc/model-base" import { Authorization } from "../Authorization" import { Fraudio } from "../Fraudio" import { clear } from "../utilities" import * as utilities from "../utilities" import { Card } from "./Card" import { Contact } from "./Contact" import { Items } from "./Items" import { Merchant } from "./Merchant" export interface FailedAuthorization { merchant: Merchant | { id: authly.Identifier } authorization: { id: string number: string amount: number items?: number | Items currency?: isoly.Currency card?: Card contact?: Contact capture?: "auto" descriptor?: string recurring?: Authorization.Recurring verification?: "verified" | "unavailable" | "rejected" status: "failed"[] history: Authorization.History[] reason: string declinedBy?: "issuer" | "intergiro" created: isoly.DateTime category?: "purchase" | "withdrawal" | "payout" fraudio?: Fraudio processor?: Partial } } export namespace FailedAuthorization { export function is(value: any | FailedAuthorization): value is FailedAuthorization { return ( typeof value == "object" && (Merchant.is(value.merchant) || (typeof value.merchant == "object" && authly.Identifier.is(value.merchant.id))) && typeof value.authorization == "object" && typeof value.authorization.id == "string" && typeof value.authorization.number == "string" && typeof value.authorization.amount == "number" && (value.authorization.items == undefined || typeof value.authorization.items == "number" || Items.is(value.authorization.items)) && (value.authorization.currency == undefined || isoly.Currency.is(value.authorization.currency)) && (value.authorization.card == undefined || Card.is(value.authorization.card)) && (value.authorization.contact == undefined || Contact.is(value.authorization.contact)) && (value.authorization.capture == undefined || value.authorization.capture == "auto") && (value.authorization.descriptor == undefined || typeof value.authorization.descriptor == "string") && (value.authorization.recurring == undefined || Authorization.Recurring.is(value.authorization.recurring)) && [undefined, "verified", "unavailable", "rejected"].includes(value.authorization.verification) && Array.isArray(value.authorization.status) && value.authorization.status.every((s: any) => s == "failed") && typeof value.authorization.reason == "string" && (value.authorization.declinedBy == undefined || value.authorization.declinedBy == "issuer" || value.authorization.declinedBy == "intergiro") && isoly.DateTime.is(value.authorization.created) && Array.isArray(value.authorization.history) && value.authorization.history.every(Authorization.History.is) && (value.authorization.category == undefined || value.authorization.category == "purchase" || value.authorization.category == "withdrawal" || value.authorization.category == "payout") && (value.fraudio == undefined || Fraudio.is(value.fraudio)) && (value.processor == undefined || Authorization.Processor.is(value.processor)) ) } export function from(history: Authorization.History[], id: authly.Identifier): FailedAuthorization | undefined { let result: FailedAuthorization | undefined const historyWithAmount = history.find(h => "amount" in h) if (history.length > 0 && historyWithAmount && "amount" in historyWithAmount && historyWithAmount.amount) { result = { merchant: { id: history[0].merchant }, authorization: { id, status: ["failed"], created: "", reason: "unknown error", number: history[0].number, history, amount: historyWithAmount.amount, }, } for (const entry of history.sort((a, b) => (a.date > b.date ? 1 : -1))) { result.authorization.amount = "amount" in entry && entry.amount ? entry.amount : result.authorization.amount result.authorization.items = "items" in entry && base.Item.canBe(entry.items) ? Items.from(entry.items) : result.authorization.items result.authorization.currency = "currency" in entry ? entry.currency : result.authorization.currency result.authorization.descriptor = "descriptor" in entry ? entry.descriptor : result.authorization.descriptor result.authorization.card = "card" in entry && entry.card ? entry.card : result.authorization.card result.authorization.contact = "contact" in entry && entry.contact && (base.Contact.is(entry.contact) || Contact.is(entry.contact)) ? Contact.from(entry.contact) : result.authorization.contact result.authorization.recurring = "recurring" in entry ? entry.recurring : result.authorization.recurring result.authorization.reason = "reason" in entry ? entry.reason : result.authorization.reason result.authorization.declinedBy = "declinedBy" in entry ? entry.declinedBy : result.authorization.declinedBy result.authorization.created = entry.date result.authorization.verification = "verification" in entry ? entry.verification : result.authorization.verification result.authorization.fraudio = "fraudio" in entry ? entry.fraudio : result.authorization.fraudio result.authorization.processor = !("processor" in entry) || result.authorization.processor ? result.authorization.processor : undefined } result = clear(result) } return result } export function load(histories: Authorization.History[], id: authly.Identifier): FailedAuthorization[] { const record: Record = {} for (const history of histories) record[history.number] = [...(record[history.number] ?? []), history] return Object.values(record) .map(e => from(e, id)) .filter(utilities.isDefined) } }