Skip to content

Commit

Permalink
Bugfix/MOL-587: Potential Bug: autoRefund triggered in CT but not tri…
Browse files Browse the repository at this point in the history
…ggered to complete in Mollie
  • Loading branch information
NghiaDTr committed Dec 11, 2024
1 parent abe58bd commit 9c5680a
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 567 deletions.
197 changes: 196 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,202 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

## v1.2.0-alpha
## v1.2.1

Added

- New custom field for transaction: `sctm_transaction_refund_for_mollie_payment` which would store the Mollie Payment ID that need to be refunded

Fixes

[Create Refund](./docs/CreateRefund.md)
- Handling the Refund Creation for the case that the Payment has more than one Success Charge transaction
- Changing the way to determine the Create Refund action:
- Before
```Typescript
// processor/src/utils/paymentAction.utils.ts

if (groups.successCharge.length === 1 && groups.initialRefund.length) {
return ConnectorActions.CreateRefund;
}
```

- After
```Typescript
// processor/src/utils/paymentAction.utils.ts
if (groups.successCharge.length >= 1 && groups.initialRefund.length) {
return ConnectorActions.CreateRefund;
}
```

- We are supporting to create the refund for the payment which has more than one Success Charge transactions
- By default, we will create the Refund for the latest Success Charge transaction. For example:
```Typescript
// CommerceTools Payment
{
id: 'payment-id',
transactions: [
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_123456' // Mollie Payment ID
},
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_999999' // Mollie Payment ID
},
{
type: 'Refund',
state: 'Initial', // Creating a Refund for the Mollie Payment tr_999999
},
]
}
```

- However, you can also specify the Mollie Payment ID (which stored in the `interactionId` of the Success Charge transaction) that you want to create a refund for by adding the Mollie Payment ID to the custom field `sctm_transaction_refund_for_mollie_payment` of the Initial Refund transaction. For example:

```Typescript
// CommerceTools Payment
{
id: 'payment-id',
transactions: [
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_123456' // Mollie Payment ID
},
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_999999' // Mollie Payment ID
},
{
type: 'Refund',
state: 'Initial',
custom: {
type: {
...
},
fields: {
sctm_transaction_refund_for_mollie_payment: 'tr_123456' // Creating a Refund for the Mollie Payment tr_123456
}
}
},
]
}
```

[Cancel Refund](./docs/CancelPaymentRefund.md)
- Following the changes for creating refund, we also updated the handler for Refund Cancellation to match with the above changes
- Changing the way to determine the Cancel Refund action:
- Before
```Typescript
// processor/src/utils/paymentAction.utils.ts
if (
groups.successCharge.length === 1 &&
groups.pendingRefund.length === 1 &&
groups.initialCancelAuthorization.length === 1
) {
return ConnectorActions.CancelRefund;
}
```

- After
```Typescript
// processor/src/utils/paymentAction.utils.ts
if (
groups.successCharge.length >= 1 &&
groups.pendingRefund.length >= 1 &&
groups.initialCancelAuthorization.length === 1
) {
return ConnectorActions.CancelRefund;
}
```

- To support the old versions, we will create the cancellation for the latest Pending Refund transaction (which is a pending refund for the latest Success Charge transaction in that payment). For example:
```Typescript
// CommerceTools Payment
{
id: 'payment-id',
transactions: [
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_123456' // Mollie Payment ID
},
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_999999' // Mollie Payment ID
},
{
id: 'refund-transaction-1',
type: 'Refund',
state: 'Pending',
interactionId: 're_123456', // Mollie Refund ID
},
{
id: 'refund-transaction-2',
type: 'Refund',
state: 'Pending',
interactionId: 're_999999', // Mollie Refund ID
},
{
type: 'CancelAuthorization',
state: 'Initial'
// interactionId is not set
}
]
}
// In this case, this will be considered as a Cancellation request for the Pending Refund with id: refund-transaction-2
```
__*Note:* The above solution is just for supporting the old versions and will be remove in the near future (in next versions). From this version, please follow the below solution.__

- However, to do it in a correct way, from this version, you should specify the Mollie Refund ID (which stored in the `interactionId` of the Pending Refund transaction) that you want to cancel by putting it in the `interactionId` of the Initial CancelAuthorization. For example:
```Typescript
// CommerceTools Payment
{
id: 'payment-id',
transactions: [
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_123456' // Mollie Payment ID
},
{
type: 'Charge',
state: 'Success',
interactionId: 'tr_999999' // Mollie Payment ID
},
{
id: 'refund-transaction-1',
type: 'Refund',
state: 'Pending',
interactionId: 're_123456', // Mollie Refund ID
},
{
id: 'refund-transaction-2',
type: 'Refund',
state: 'Pending',
interactionId: 're_999999', // Mollie Refund ID
},
{
type: 'CancelAuthorization',
state: 'Initial',
interactionId: 're_123456' // Mollie Refund ID that you want to cancel
}
]
}
// In this case, this will be considered as a Cancellation request for the Pending Refund with id: refund-transaction-1
```

## v1.2.0

Added

Expand Down
6 changes: 6 additions & 0 deletions docs/CancelPaymentRefund.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* [Parameters map](#parameters-map)
* [Representation: CT Payment](#representation-ct-payment)
* [Creating CommerceTools actions from Mollie's response](#creating-commercetools-actions-from-mollies-response)
* [Update per version](#update-per-version)

## Overview
This functionality is used to cancel the pending refund which means it is created but not complete yet.
Expand Down Expand Up @@ -155,3 +156,8 @@ When order is successfully cancelled on Mollie, we update commercetools payment
| `changeTransactionState` | `transactionId: <pendingRefundTransactionId>, state: 'Failure'` |
| `changeTransactionState` | `transactionId: <initialCancelAuthorizationTransactionId>, state: 'Success'` |
| `setTransactionCustomType` | `transactionId: <pendingRefundTransactionId>, type.key:sctm_payment_cancel_reason, fields: {reasonText: "cancellation reason", statusText: "cancelled from shop side"}` |

## Update per version

The function was updated at:
- [v1.2.1](../CHANGELOG.md#v121)
10 changes: 7 additions & 3 deletions docs/CreateRefund.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* [Parameters map](#parameters-map)
* [Representation: CommerceTools Payment](#representation-ct-payment)
* [Creating commercetools actions from Mollie's response](#creating-commercetools-actions-from-mollies-response)
* [Update per version](#update-per-version)

## Overview

Expand All @@ -24,8 +25,6 @@ A transaction with type "Refund" and state "Initial" triggers a refund.

In commercetools, we have a Payment which has one Transaction. This maps to an order in mollie. The commercetools Payment's key is the mollie orderId, and the commercetools Transaction maps to the payment in mollie.

In commercetools, we have a Payment which has one Transaction. This maps to an order in mollie. The commercetools Payment's key is the mollie orderId, and the commercetools Transaction maps to the payment in mollie.

```
{
id: "c0887a2d-bfbf-4f77-8f3d-fc33fb4c0920",
Expand Down Expand Up @@ -96,4 +95,9 @@ transactions: [
]
```

When the refund is completed, this transaction's state will be updated by the notifications module to "Success" or "Failure".
When the refund is completed, this transaction's state will be updated by the notifications module to "Success" or "Failure".

## Update per version

The function was updated at:
- [v1.2.1](../CHANGELOG.md#v121)
82 changes: 81 additions & 1 deletion processor/src/commercetools/customFields.commercetools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export async function createTransactionSurchargeCustomType(): Promise<void> {
.types()
.post({
body: {
key: CustomFields.createPayment.interfaceInteraction.key,
key: CustomFields.transactionSurchargeCost,
name: {
en: 'SCTM - Transaction surcharge amount',
de: 'SCTM - Betrag des Transaktionszuschlags',
Expand Down Expand Up @@ -379,3 +379,83 @@ export async function createTransactionSurchargeCustomType(): Promise<void> {
return;
}
}

export async function createTransactionRefundForMolliePaymentCustomType(): Promise<void> {
const apiRoot = createApiRoot();
const customFields: FieldDefinition[] = [
{
name: CustomFields.transactionRefundForMolliePayment,
label: {
en: 'Identify the Mollie payment which is being refunded',
de: 'Identifizieren Sie die Mollie-Zahlung, die zurückerstattet wird',
},
required: false,
type: {
name: 'String',
},
inputHint: 'MultiLine',
},
];

const {
body: { results: types },
} = await apiRoot
.types()
.get({
queryArgs: {
where: `key = "${CustomFields.transactionRefundForMolliePayment}"`,
},
})
.execute();

if (types.length <= 0) {
await apiRoot
.types()
.post({
body: {
key: CustomFields.transactionRefundForMolliePayment,
name: {
en: 'Identify the Mollie payment which is being refunded',
de: 'Identifizieren Sie die Mollie-Zahlung, die zurückerstattet wird',
},
resourceTypeIds: ['transaction'],
fieldDefinitions: customFields,
},
})
.execute();

return;
}

const type = types[0];
const definitions = type.fieldDefinitions;

if (definitions.length > 0) {
const actions: TypeUpdateAction[] = [];
definitions.forEach((definition) => {
actions.push({
action: 'removeFieldDefinition',
fieldName: definition.name,
});
});
customFields.forEach((field) => {
actions.push({
action: 'addFieldDefinition',
fieldDefinition: field,
});
});

await apiRoot
.types()
.withKey({ key: CustomFields.transactionRefundForMolliePayment })
.post({
body: {
version: type.version,
actions,
},
})
.execute();

return;
}
}
2 changes: 2 additions & 0 deletions processor/src/service/connector.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
createCustomPaymentInterfaceInteractionType,
createCustomPaymentTransactionCancelReasonType,
createTransactionSurchargeCustomType,
createTransactionRefundForMolliePaymentCustomType,
} from '../commercetools/customFields.commercetools';
export const createExtensionAndCustomFields = async (extensionUrl: string): Promise<void> => {
await createPaymentExtension(extensionUrl);
await createCustomPaymentType();
await createCustomPaymentInterfaceInteractionType();
await createCustomPaymentTransactionCancelReasonType();
await createTransactionSurchargeCustomType();
await createTransactionRefundForMolliePaymentCustomType();
};

export const removeExtension = async (): Promise<void> => {
Expand Down
Loading

0 comments on commit 9c5680a

Please sign in to comment.