feat(dashboard,core-flows,js-sdk,types,link-modules,payment): ability to copy payment link (#8630)

what: 

- enables a button to create a payment link when a payment delta is present
- api to delete order payment collection
- adds a pending amount to payment collections

Note: Not the happiest with the decision on when to create a payment collection and when not to. The code should programatically create or delete payment collections currently to generate the right collection for the payment delta. Adding a more specific flow to create and manage a payment collection will help reduce this burden from the code path and onto CX/merchant.

Another issue I found is that the payment collection status doesn't get updated when payment is complete as it still gets stuck to "authorized" state

https://github.com/user-attachments/assets/037a10f9-3621-43c2-94ba-1ada4b0a041b
This commit is contained in:
Riqwan Thamir
2024-08-20 12:30:17 +02:00
committed by GitHub
parent 69830ca89c
commit fa44e3f5a8
35 changed files with 631 additions and 94 deletions
@@ -0,0 +1,49 @@
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export interface DeleteEntitiesStepType {
moduleRegistrationName: string
invokeMethod: string
compensateMethod: string
entityIdentifier?: string
data: any[]
}
export const deleteEntitiesStepId = "delete-entities-step"
/**
* This step deletes one or more entities.
*/
export const deleteEntitiesStep = createStep(
deleteEntitiesStepId,
async (input: DeleteEntitiesStepType, { container }) => {
const {
moduleRegistrationName,
invokeMethod,
compensateMethod,
data = [],
} = input
const module = container.resolve<any>(moduleRegistrationName)
data.length ? await module[invokeMethod](data) : []
return new StepResponse(void 0, {
entityIdentifiers: input.data,
moduleRegistrationName,
compensateMethod,
})
},
async (compensateInput, { container }) => {
const {
entityIdentifiers = [],
moduleRegistrationName,
compensateMethod,
} = compensateInput!
if (!entityIdentifiers?.length) {
return
}
const module = container.resolve<any>(moduleRegistrationName)
await module[compensateMethod](entityIdentifiers)
}
)
@@ -65,13 +65,12 @@ export const createOrderPaymentCollectionWorkflow = createWorkflow(
const paymentCollection = useRemoteQueryStep({
entry_point: "payment_collection",
fields: ["id"],
fields: ["id", "status"],
variables: {
id: orderPaymentCollectionIds,
status: [
PaymentCollectionStatus.NOT_PAID,
PaymentCollectionStatus.AWAITING,
],
filters: {
id: orderPaymentCollectionIds,
status: [PaymentCollectionStatus.NOT_PAID],
},
},
list: false,
}).config({ name: "payment-collection-query" })
@@ -81,10 +80,7 @@ export const createOrderPaymentCollectionWorkflow = createWorkflow(
const paymentCollectionData = transform(
{ order, input },
({ order, input }) => {
const pendingPayment = MathBN.sub(
order.summary.raw_current_order_total,
order.summary.raw_original_order_total
)
const pendingPayment = order.summary.raw_pending_difference
if (MathBN.lte(pendingPayment, 0)) {
throw new MedusaError(
@@ -93,7 +89,10 @@ export const createOrderPaymentCollectionWorkflow = createWorkflow(
)
}
if (input.amount && MathBN.gt(input.amount, pendingPayment)) {
if (
input.amount &&
MathBN.gt(input.amount ?? pendingPayment, pendingPayment)
) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
`Cannot create a payment collection for amount greater than ${pendingPayment}`
@@ -0,0 +1,47 @@
import { PaymentCollectionDTO } from "@medusajs/types"
import { MedusaError, Modules, PaymentCollectionStatus } from "@medusajs/utils"
import {
WorkflowData,
createStep,
createWorkflow,
} from "@medusajs/workflows-sdk"
import { removeRemoteLinkStep, useRemoteQueryStep } from "../../common"
/**
* This step validates that the order doesn't have an active payment collection.
*/
export const throwUnlessStatusIsNotPaid = createStep(
"validate-payment-collection",
({ paymentCollection }: { paymentCollection: PaymentCollectionDTO }) => {
if (paymentCollection.status !== PaymentCollectionStatus.NOT_PAID) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
`Can only delete payment collections where status is not_paid`
)
}
}
)
export const deleteOrderPaymentCollectionsId =
"delete-order-payment-collectionworkflow"
/**
* This workflow deletes one or more invites.
*/
export const deleteOrderPaymentCollections = createWorkflow(
deleteOrderPaymentCollectionsId,
(input: WorkflowData<{ id: string }>): WorkflowData<void> => {
const paymentCollection = useRemoteQueryStep({
entry_point: "payment_collection",
fields: ["id", "status"],
variables: { id: input.id },
throw_if_key_not_found: true,
list: false,
}).config({ name: "payment-collection-query" })
throwUnlessStatusIsNotPaid({ paymentCollection })
removeRemoteLinkStep({
[Modules.PAYMENT]: { payment_collection_id: input.id },
})
}
)
@@ -27,6 +27,7 @@ export * from "./create-shipment"
export * from "./decline-order-change"
export * from "./delete-order-change"
export * from "./delete-order-change-actions"
export * from "./delete-order-payment-collection"
export * from "./exchange/begin-order-exchange"
export * from "./exchange/cancel-begin-order-exchange"
export * from "./exchange/cancel-exchange"