import type { CustomerReference, InvalidOperationError, Payment, PaymentAddInterfaceInteractionAction, PaymentAddTransactionAction, PaymentChangeAmountPlannedAction, PaymentChangeTransactionInteractionIdAction, PaymentChangeTransactionStateAction, PaymentChangeTransactionTimestampAction, PaymentSetAnonymousIdAction, PaymentSetCustomerAction, PaymentSetCustomFieldAction, PaymentSetCustomTypeAction, PaymentSetInterfaceIdAction, PaymentSetKeyAction, PaymentSetMethodInfoAction, PaymentSetMethodInfoCustomFieldAction, PaymentSetMethodInfoCustomTypeAction, PaymentSetMethodInfoInterfaceAccountAction, PaymentSetMethodInfoInterfaceAction, PaymentSetMethodInfoMethodAction, PaymentSetMethodInfoNameAction, PaymentSetMethodInfoTokenAction, PaymentSetStatusInterfaceCodeAction, PaymentSetStatusInterfaceTextAction, PaymentSetTransactionCustomFieldAction, PaymentSetTransactionCustomTypeAction, PaymentSetTransactionInterfaceIdAction, PaymentTransitionStateAction, PaymentUpdateAction, ReferencedResourceNotFoundError, State, Transaction, } from "@commercetools/platform-sdk"; import { CommercetoolsError } from "#src/exceptions.ts"; import type { Writable } from "#src/types.ts"; import type { RepositoryContext, UpdateHandlerInterface } from "../abstract.ts"; import { AbstractUpdateHandler } from "../abstract.ts"; import { createCentPrecisionMoney, createCustomFields, getReferenceFromResourceIdentifier, } from "../helpers.ts"; import { transactionFromTransactionDraft } from "./helpers.ts"; export class PaymentUpdateHandler extends AbstractUpdateHandler implements UpdateHandlerInterface { async addInterfaceInteraction( context: RepositoryContext, resource: Writable, { type, fields }: PaymentAddInterfaceInteractionAction, ) { const customFields = await createCustomFields( { type, fields }, context.projectKey, this._storage, ); resource.interfaceInteractions.push(customFields!); } async addTransaction( context: RepositoryContext, resource: Writable, { transaction }: PaymentAddTransactionAction, ) { resource.transactions = [ ...resource.transactions, await transactionFromTransactionDraft( context, this._storage, transaction, ), ]; } changeAmountPlanned( _context: RepositoryContext, resource: Writable, { amount }: PaymentChangeAmountPlannedAction, ) { resource.amountPlanned = createCentPrecisionMoney(amount); } changeTransactionInteractionId( _context: RepositoryContext, resource: Writable, { transactionId, interactionId, }: PaymentChangeTransactionInteractionIdAction, ) { const transaction = resource.transactions.find( (e: Transaction) => e.id === transactionId, ); if (transaction) { transaction.interactionId = interactionId; } } setTransactionInterfaceId( _context: RepositoryContext, resource: Writable, { transactionId, interfaceId }: PaymentSetTransactionInterfaceIdAction, ) { const transaction = resource.transactions.find( (e: Transaction) => e.id === transactionId, ); if (transaction) { transaction.interfaceId = interfaceId; } } changeTransactionState( _context: RepositoryContext, resource: Writable, { transactionId, state }: PaymentChangeTransactionStateAction, ) { const index = resource.transactions.findIndex( (e: Transaction) => e.id === transactionId, ); const updatedTransaction: Transaction = { ...resource.transactions[index], state, }; resource.transactions[index] = updatedTransaction; } changeTransactionTimestamp( _context: RepositoryContext, resource: Writable, { transactionId, timestamp }: PaymentChangeTransactionTimestampAction, ) { const transaction = resource.transactions.find( (e: Transaction) => e.id === transactionId, ); if (transaction) { transaction.timestamp = timestamp; } } setAnonymousId( _context: RepositoryContext, resource: Writable, { anonymousId }: PaymentSetAnonymousIdAction, ) { resource.anonymousId = anonymousId; resource.customer = undefined; } async setCustomer( _context: RepositoryContext, resource: Writable, { customer }: PaymentSetCustomerAction, ) { if (customer) { const c = await getReferenceFromResourceIdentifier( customer, _context.projectKey, this._storage, ); resource.customer = c; resource.anonymousId = undefined; } } setCustomField( context: RepositoryContext, resource: Payment, { name, value }: PaymentSetCustomFieldAction, ) { this._setCustomFieldValues(resource, { name, value }); } async setCustomType( context: RepositoryContext, resource: Writable, { type, fields }: PaymentSetCustomTypeAction, ) { await this._setCustomType(context, resource, { type, fields }); } setInterfaceId( _context: RepositoryContext, resource: Writable, { interfaceId }: PaymentSetInterfaceIdAction, ) { resource.interfaceId = interfaceId; } setKey( _context: RepositoryContext, resource: Writable, { key }: PaymentSetKeyAction, ) { resource.key = key; } setMethodInfoInterface( _context: RepositoryContext, resource: Writable, args: PaymentSetMethodInfoInterfaceAction, ) { resource.paymentMethodInfo.paymentInterface = args.interface; } setMethodInfoMethod( _context: RepositoryContext, resource: Writable, { method }: PaymentSetMethodInfoMethodAction, ) { resource.paymentMethodInfo.method = method; } setMethodInfoName( _context: RepositoryContext, resource: Writable, { name }: PaymentSetMethodInfoNameAction, ) { resource.paymentMethodInfo.name = name; } setStatusInterfaceCode( _context: RepositoryContext, resource: Writable, { interfaceCode }: PaymentSetStatusInterfaceCodeAction, ) { resource.paymentStatus.interfaceCode = interfaceCode; } setStatusInterfaceText( _context: RepositoryContext, resource: Writable, { interfaceText }: PaymentSetStatusInterfaceTextAction, ) { resource.paymentStatus.interfaceText = interfaceText; } setTransactionCustomField( _context: RepositoryContext, resource: Writable, { transactionId, name, value }: PaymentSetTransactionCustomFieldAction, ) { const transaction = resource.transactions.find( (e: Transaction) => e.id === transactionId, ); if (transaction) { if (!transaction.custom) { throw new CommercetoolsError({ code: "InvalidOperation", message: "Transaction has no custom field", }); } transaction.custom.fields[name] = value; } } async setTransactionCustomType( context: RepositoryContext, resource: Writable, { transactionId, type, fields }: PaymentSetTransactionCustomTypeAction, ) { const transaction = resource.transactions.find( (e: Transaction) => e.id === transactionId, ); if (transaction) { if (!type) { transaction.custom = undefined; } else { const resolvedType = await this._storage.getByResourceIdentifier( context.projectKey, type, ); if (!resolvedType) { throw new CommercetoolsError({ code: "ReferencedResourceNotFound", message: `Type ${type} not found`, typeId: "type", }); } transaction.custom = { type: { typeId: "type", id: resolvedType.id, }, fields: fields ?? {}, }; } } } async transitionState( context: RepositoryContext, resource: Writable, { state }: PaymentTransitionStateAction, ) { const stateObj = (await this._storage.getByResourceIdentifier( context.projectKey, state, )) as State | null; if (!stateObj) { throw new CommercetoolsError({ code: "ReferencedResourceNotFound", message: `State ${state} not found`, typeId: "state", }); } resource.paymentStatus.state = { typeId: "state", id: stateObj.id, obj: stateObj, }; } setMethodInfo( context: RepositoryContext, resource: Writable, { paymentInterface, method, name, interfaceAccount, token, }: PaymentSetMethodInfoAction, ) { if (paymentInterface !== undefined) { resource.paymentMethodInfo.paymentInterface = paymentInterface; } if (method !== undefined) { resource.paymentMethodInfo.method = method; } if (name !== undefined) { resource.paymentMethodInfo.name = name; } if (interfaceAccount !== undefined) { resource.paymentMethodInfo.interfaceAccount = interfaceAccount; } if (token !== undefined) { resource.paymentMethodInfo.token = token; } } setMethodInfoCustomField( context: RepositoryContext, resource: Writable, { name, value }: PaymentSetMethodInfoCustomFieldAction, ) { if (!resource.paymentMethodInfo.custom) { throw new CommercetoolsError({ code: "InvalidOperation", message: "PaymentMethodInfo has no custom field", }); } resource.paymentMethodInfo.custom.fields[name] = value; } async setMethodInfoCustomType( context: RepositoryContext, resource: Writable, { type, fields }: PaymentSetMethodInfoCustomTypeAction, ) { if (!type) { resource.paymentMethodInfo.custom = undefined; } else { const resolvedType = await this._storage.getByResourceIdentifier( context.projectKey, type, ); if (!resolvedType) { throw new CommercetoolsError({ code: "ReferencedResourceNotFound", message: `Type ${type} not found`, typeId: "type", }); } resource.paymentMethodInfo.custom = { type: { typeId: "type", id: resolvedType.id, }, fields: fields ?? {}, }; } } setMethodInfoInterfaceAccount( _context: RepositoryContext, resource: Writable, { interfaceAccount }: PaymentSetMethodInfoInterfaceAccountAction, ) { resource.paymentMethodInfo.interfaceAccount = interfaceAccount; } setMethodInfoToken( _context: RepositoryContext, resource: Writable, { token }: PaymentSetMethodInfoTokenAction, ) { resource.paymentMethodInfo.token = token; } }