feat: implement Cash on Delivery (COD) payment method

This commit adds comprehensive COD support using Saleor's native Transaction system:

**Architecture:**
- Uses Saleor's native Transaction objects (not metadata)
- Modular payment method configuration
- Extensible design for future payment types (cards, bank transfer, etc.)

**New Components:**
- PaymentMethodSelector: Reusable payment method selection UI
- PaymentMethodCard: Individual payment method card
- CODInstructions: COD-specific instructions and guidance
- PaymentSection: Checkout integration wrapper

**Core Features:**
- COD selected by default for Serbia (default-channel)
- Transaction created automatically on order completion
- Transaction visible in Saleor Dashboard
- Multi-language support (EN, SR, DE, FR)
- No additional fees
- Instructions shown to customer (prepare cash, inspect order, no fee)

**Files Added:**
- docs/COD-IMPLEMENTATION-PLAN.md
- src/lib/config/paymentMethods.ts
- src/lib/saleor/payments/types.ts
- src/lib/saleor/payments/cod.ts
- src/components/payment/PaymentMethodSelector.tsx
- src/components/payment/PaymentMethodCard.tsx
- src/components/payment/CODInstructions.tsx
- src/components/payment/index.ts
- src/app/[locale]/checkout/components/PaymentSection.tsx

**Files Modified:**
- src/app/[locale]/checkout/page.tsx (added payment section, transaction creation)
- src/i18n/messages/{en,sr,de,fr}.json (payment translations)

**Technical Details:**
- Transaction status: NOT_CHARGED
- Available actions: [CHARGE]
- PSP Reference format: COD-{orderNumber}-{timestamp}
- Staff collects cash and fulfills order via Dashboard

Closes: Cash on Delivery payment implementation
This commit is contained in:
Unchained
2026-03-29 06:02:51 +02:00
parent 6f9081cb52
commit ff481f18c3
14 changed files with 1067 additions and 5 deletions

View File

@@ -383,6 +383,37 @@
"thankYou": "Vielen Dank für Ihren Einkauf.",
"orderNumber": "Bestellnummer",
"confirmationEmail": "Sie erhalten in Kürze eine Bestätigungs-E-Mail. Wir werden Sie kontaktieren, um Nachnahme zu arrangieren.",
"continueShoppingBtn": "Weiter einkaufen"
"continueShoppingBtn": "Weiter einkaufen",
"errorSelectPayment": "Bitte wählen Sie eine Zahlungsmethode."
},
"Payment": {
"title": "Zahlungsmethode",
"selectMethod": "Zahlungsmethode wählen",
"securePayment": "Sichere Zahlungsabwicklung",
"noMethodsAvailable": "Keine Zahlungsmethoden verfügbar",
"singleMethodNotice": "Nachnahme ist die einzige verfügbare Zahlungsmethode für Ihren Standort",
"COD": {
"name": "Nachnahme",
"description": "Bezahlen Sie bei Erhalt Ihrer Bestellung",
"instructions": {
"title": "Zahlungsanweisungen",
"prepareCash": "Bargeld vorbereiten",
"prepareCashDesc": "Bitte haben Sie den genauen Betrag in bar bereit",
"inspectOrder": "Vor Zahlung prüfen",
"inspectOrderDesc": "Sie können Ihre Bestellung vor der Zahlung überprüfen",
"noFee": "Keine zusätzliche Gebühr",
"noFeeDesc": "Nachnahme ist völlig kostenlos"
}
},
"card": {
"name": "Kreditkarte",
"description": "Sichere Online-Zahlung",
"comingSoon": "Demnächst verfügbar"
},
"bank_transfer": {
"name": "Banküberweisung",
"description": "Bezahlen Sie per Banküberweisung",
"comingSoon": "Demnächst verfügbar"
}
}
}

View File

@@ -430,6 +430,37 @@
"thankYou": "Thank you for your purchase.",
"orderNumber": "Order Number",
"confirmationEmail": "You will receive a confirmation email shortly. We will contact you to arrange Cash on Delivery.",
"continueShoppingBtn": "Continue Shopping"
"continueShoppingBtn": "Continue Shopping",
"errorSelectPayment": "Please select a payment method."
},
"Payment": {
"title": "Payment Method",
"selectMethod": "Select payment method",
"securePayment": "Secure payment processing",
"noMethodsAvailable": "No payment methods available",
"singleMethodNotice": "Cash on Delivery is the only available payment method for your location",
"COD": {
"name": "Cash on Delivery",
"description": "Pay when you receive your order",
"instructions": {
"title": "Payment Instructions",
"prepareCash": "Prepare Cash",
"prepareCashDesc": "Please have the exact amount ready in cash",
"inspectOrder": "Inspect Before Paying",
"inspectOrderDesc": "You can check your order before making payment",
"noFee": "No Extra Fee",
"noFeeDesc": "Cash on Delivery is completely free"
}
},
"card": {
"name": "Credit Card",
"description": "Secure online payment",
"comingSoon": "Coming soon"
},
"bank_transfer": {
"name": "Bank Transfer",
"description": "Pay via bank transfer",
"comingSoon": "Coming soon"
}
}
}

View File

@@ -383,6 +383,37 @@
"thankYou": "Merci pour votre achat.",
"orderNumber": "Numéro de Commande",
"confirmationEmail": "Vous recevrez bientôt un email de confirmation. Nous vous contacterons pour organiser le paiement contre-remboursement.",
"continueShoppingBtn": "Continuer les Achats"
"continueShoppingBtn": "Continuer les Achats",
"errorSelectPayment": "Veuillez sélectionner un mode de paiement."
},
"Payment": {
"title": "Mode de Paiement",
"selectMethod": "Sélectionner le mode de paiement",
"securePayment": "Paiement sécurisé",
"noMethodsAvailable": "Aucun mode de paiement disponible",
"singleMethodNotice": "Le paiement à la livraison est le seul mode de paiement disponible pour votre région",
"COD": {
"name": "Paiement à la Livraison",
"description": "Payez lors de la réception de votre commande",
"instructions": {
"title": "Instructions de Paiement",
"prepareCash": "Préparer l'Argent",
"prepareCashDesc": "Veuillez préparer le montant exact en espèces",
"inspectOrder": "Inspecter Avant de Payer",
"inspectOrderDesc": "Vous pouvez vérifier votre commande avant de payer",
"noFee": "Pas de Frais Supplémentaires",
"noFeeDesc": "Le paiement à la livraison est entièrement gratuit"
}
},
"card": {
"name": "Carte de Crédit",
"description": "Paiement en ligne sécurisé",
"comingSoon": "Bientôt disponible"
},
"bank_transfer": {
"name": "Virement Bancaire",
"description": "Payez par virement bancaire",
"comingSoon": "Bientôt disponible"
}
}
}

View File

@@ -429,6 +429,37 @@
"thankYou": "Hvala vam na kupovini!",
"orderNumber": "Broj narudžbine",
"confirmationEmail": "Uскoro ćete primiti email potvrde. Kontaktiraćemo vas da dogovorimo pouzećem plaćanje.",
"continueShoppingBtn": "Nastavi kupovinu"
"continueShoppingBtn": "Nastavi kupovinu",
"errorSelectPayment": "Molimo izaberite način plaćanja."
},
"Payment": {
"title": "Način Plaćanja",
"selectMethod": "Izaberite način plaćanja",
"securePayment": "Bezbedno plaćanje",
"noMethodsAvailable": "Nema dostupnih načina plaćanja",
"singleMethodNotice": "Plaćanje pouzećem je jedini dostupan način plaćanja za vašu lokaciju",
"COD": {
"name": "Plaćanje Pouzećem",
"description": "Platite kada primite porudžbinu",
"instructions": {
"title": "Uputstva za Plaćanje",
"prepareCash": "Pripremite Gotovinu",
"prepareCashDesc": "Molimo pripremite tačan iznos u gotovini",
"inspectOrder": "Pregledajte Pre Plaćanja",
"inspectOrderDesc": "Možete pregledati porudžbinu pre nego što platite",
"noFee": "Bez Dodatne Naknade",
"noFeeDesc": "Plaćanje pouzećem je potpuno besplatno"
}
},
"card": {
"name": "Kreditna Kartica",
"description": "Bezbedno online plaćanje",
"comingSoon": "Uskoro dostupno"
},
"bank_transfer": {
"name": "Bankovni Transfer",
"description": "Platite putem bankovnog transfera",
"comingSoon": "Uskoro dostupno"
}
}
}