Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fcece91
CET-926/feat: EOM Terms for presta plugin
SalmanTwo Nov 21, 2025
f89cbeb
CET-926/feat: Improved handling of error cases
SalmanTwo Jan 12, 2026
56703a9
Merge pull request #20 from two-inc/shabib/cet-926-eom-style-order-te…
SalmanTwo Jan 14, 2026
0fa488b
KNA-3211/feat: Enabling invoice upload and minor improvements
SalmanTwo Jan 22, 2026
08278a5
Merge pull request #22 from two-inc/shabib/kna-3211-enable-invoice-up…
SalmanTwo Feb 25, 2026
2cfb1f1
KNA-3366/feat: Basic tests and general order logic improvements
SalmanTwo Feb 26, 2026
221cadf
KNA-3366/feat: Additional test and improvements
SalmanTwo Feb 26, 2026
d5b1caf
KNA-3366/fix: Explicitly terminate non-AJAX order intent requests
SalmanTwo Feb 26, 2026
28deb06
KNA-3366/feat: Translation coverage and updating Two order details view
SalmanTwo Feb 26, 2026
8c13b46
KNA-3366/feat: Updated Translations
SalmanTwo Feb 26, 2026
705514e
KNA-3366/feat: More robust order intent behaviour
SalmanTwo Mar 3, 2026
51c812f
PDEV-3366/feat: Corrected positioning for country selector in address…
SalmanTwo Mar 9, 2026
8daebe3
PDEV-3366/feat: Optional toggle for tax subtotals
SalmanTwo Mar 9, 2026
00be1ae
PDEV-3366/feat: General improvements
SalmanTwo Mar 10, 2026
2c13ef5
PDEV-3366/feat: Better order intent handling and using natvie presta …
SalmanTwo Mar 10, 2026
fcbc793
PDEV-3366/feat: Better discount handling and general improvements
SalmanTwo Mar 10, 2026
3411640
PDEV-3366/feat: Better order intent activation gate and handling eco-…
SalmanTwo Mar 10, 2026
f094d84
PDEV-3366/feat: harden Two checkout flow (strict parity, callback rec…
SalmanTwo Mar 10, 2026
61c4a13
PDEV-3366f/ix: harden order-intent security and canonicalize discount…
SalmanTwo Mar 10, 2026
ed889d0
PDEV-3366/fix: show Standard vs EOM invoice terms on buyer success sc…
SalmanTwo Mar 10, 2026
25311c3
PDEV-3366/feat:Harden ES tax-rate canonicalization (default 0.21 fall…
SalmanTwo Mar 10, 2026
f7d4d5d
PDEV-3366/feat: harden ES tax-rate snapping and mixed cart-rule disco…
SalmanTwo Mar 11, 2026
5367f2c
PDEV-3366/feat:make buyer cancel terminal, block late verified/fulfil…
SalmanTwo Mar 11, 2026
d199470
Merge pull request #23 from two-inc/shabib/kna-3366-plugin-tests-for-…
SalmanTwo Mar 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions .ai/decisions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Architectural Decisions

> **Self-updating file** - AI agents should log significant decisions here.
> Add entries at the TOP (newest first).

---

## How to Add Entries

```markdown
## [YYYY-MM-DD] Decision Title

**Context**: What problem or requirement triggered this?
**Decision**: What was decided?
**Alternatives Considered**: What else was considered?
**Rationale**: Why this approach?
**Consequences**: Trade-offs and implications
```

---

## [2026-01-22] Consolidate AI Context into CLAUDE.md

**Context**: Had both `.cursor/rules/prestashop.mdc` and `CLAUDE.md` with overlapping content.

**Decision**: Make CLAUDE.md the single source of truth with self-improvement protocols. The Cursor rules file can be removed or minimized.

**Alternatives Considered**:
- Keep both files in sync (maintenance burden)
- Keep Cursor rules as primary (not Claude-optimized)

**Rationale**:
- CLAUDE.md is auto-read by Claude
- Self-improvement instructions enable continuous enhancement
- Single source of truth prevents drift

**Consequences**:
- Non-Claude AI models in Cursor won't get detailed rules (acceptable)
- Must keep CLAUDE.md updated (AI can self-update)

---

## [2025-11-21] End-of-Month Payment Terms

**Context**: B2B customers requested payment terms aligned with accounting cycles.

**Decision**: Add `duration_days_calculated_from: "END_OF_MONTH"` API field with STANDARD/EOM type selection.

**Alternatives Considered**:
- Hardcode EOM calculation client-side (rejected: Two backend should own this)
- Only support standard terms (rejected: customer demand)

**Rationale**:
- EOM common in B2B invoicing
- Backward compatible via STANDARD default
- Clean UI separation

**Consequences**:
- New database column needed
- EOM limited to 30/45/60 days (API constraint)
- Requires Two backend support

---

## [2025-11-14] Separate Invoice Upload Service

**Context**: Invoice upload logic was getting complex with signed URLs and polling.

**Decision**: Create dedicated `TwoInvoiceUploadService.php` class.

**Alternatives Considered**:
- Keep in main module file (rejected: 4000+ lines already)
- Use PrestaShop service container (rejected: version compatibility)

**Rationale**:
- Single responsibility principle
- Easier testing and maintenance
- Clear interface

**Consequences**:
- Additional file to maintain
- Must be included/autoloaded properly

---

## [2025-10-06] Triple-Layer jQuery Fallback

**Context**: jQuery not reliably available on PrestaShop 1.7.6.x with various themes.

**Decision**: Implement three fallback layers plus JavaScript-side waiting.

**Alternatives Considered**:
- Require jQuery in theme (rejected: can't control merchant themes)
- Use vanilla JS only (rejected: massive rewrite, PrestaShop uses jQuery)
- Single CDN fallback (rejected: may still race)

**Rationale**:
- Belt-and-suspenders approach
- Guaranteed to work regardless of theme
- Minimal overhead

**Consequences**:
- Slight initialization delay in worst case
- Extra code complexity
- Pattern must be followed in all JS

---

## [2025-09-26] Server-Side Order Intent Verification

**Context**: Client-side Order Intent check could be bypassed.

**Decision**: Re-verify Order Intent server-side before creating order.

**Alternatives Considered**:
- Trust client-side only (rejected: security risk)
- Skip client-side check (rejected: poor UX)

**Rationale**:
- Defense in depth
- Payment security is non-negotiable
- Two API is idempotent

**Consequences**:
- Extra API call at order creation
- Cached result prevents duplicate calls
- Guaranteed no order without valid intent

---

## [2025-09-26] Modular JavaScript Architecture

**Context**: Needed maintainable checkout JavaScript across PrestaShop versions.

**Decision**: Split into focused modules: Manager, OrderIntent, CompanySearch, FieldValidation.

**Alternatives Considered**:
- Single monolithic file (rejected: hard to maintain)
- ES6 modules with bundler (rejected: version compatibility)

**Rationale**:
- Separation of concerns
- Individual component testing
- Clear responsibilities

**Consequences**:
- Multiple script files need load order management
- Inter-module communication via manager
- Priority-based registration required
113 changes: 113 additions & 0 deletions .ai/learnings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Learnings & Bug Fixes

> **Self-updating file** - AI agents should append new learnings when fixing bugs.
> Add entries at the TOP of each section (newest first).

---

## How to Add Entries

```markdown
### [YYYY-MM-DD] Brief Title
**Problem**: What went wrong
**Root Cause**: Why it happened
**Fix**: How it was solved
**Files**: Which files were changed
```

---

## Shipping & Tax Calculation Issues

### [2026-01-22] Shipping Missing When Free Shipping Cart Rule Active
**Problem**: Order intent `gross_amount` was €29 less than checkout total; shipping line item not included
**Root Cause**: Code used `$cart->getOrderTotal(true, Cart::ONLY_SHIPPING)` which returns **0** when a "Free shipping" cart rule is active (known PrestaShop behavior)
**Fix**: Use `$cart->getPackageShippingCost($cart->id_carrier, true)` to get carrier's actual cost BEFORE free shipping rules are applied. This method returns the carrier's configured price regardless of cart rules.
**Files**: `twopayment.php` → `getTwoProductItems()` shipping detection

### [2026-01-22] Tax Rate Shows 20% Instead of 21% (Rounding Errors)
**Problem**: Tax rate displayed as 0.200000 instead of 0.210000; calculated from amounts instead of configured rate
**Root Cause**: Code was calculating tax rate from `(gross - net) / net` which can have rounding errors
**Fix**: Use PrestaShop's native `rate` field from cart products as primary source (it's the configured tax percentage). Only fall back to calculated rate when native field is unavailable or 0 but tax was actually charged.
**Files**: `twopayment.php` → `getTwoProductItems()` tax rate calculation

### [2026-01-22] Shipping Tax Rate Not Using Carrier Configuration
**Problem**: Shipping tax rate was derived from amounts, not from carrier's configured tax rules group
**Fix**: Use `$carrier->getIdTaxRulesGroup()` + `TaxManagerFactory::getManager()` + `getTaxCalculator()` to get the actual configured shipping tax rate
**Files**: `twopayment.php` → `getTwoProductItems()` shipping tax calculation

### [2026-01-22] Store Tax Rules Not Applied (0% Tax on Products)
**Problem**: Products showed 0% tax despite "ES Standard rate (21%)" tax rule being assigned
**Root Cause**: **Store misconfiguration** - Tax rule existed but wasn't configured to apply to Spain (ES) country. This is a PrestaShop admin configuration issue, NOT a module bug.
**Fix**: Store admin needed to edit the tax rule and add Spain to the country list
**Files**: N/A - Store configuration issue

---

## jQuery & JavaScript Issues

### [2025-10-06] jQuery Race Condition on PS 1.7.6.x
**Problem**: `$ is not defined` errors on checkout
**Root Cause**: Theme-dependent jQuery loading - scripts execute before jQuery loads
**Fix**: Triple-layer PHP fallback + `waitForJQuery()` JS wrapper
**Files**: `twopayment.php`, all JS modules

---

## API Integration Issues

### [2025-11-21] Tax Rate 0% Despite Tax Applied
**Problem**: Two API rejects with tax formula validation error
**Root Cause**: PrestaShop `rate` field can be 0 even when tax exists in gross/net
**Fix**: Calculate rate from `(gross - net) / net` as source of truth
**Files**: `twopayment.php` → `buildOrderPayload()`

### [2025-11-21] Phone Validation Failures
**Problem**: "Invalid phone number" from Two API
**Root Cause**: Customer used `phone_mobile` field, `phone` was empty
**Fix**: Fallback chain: `phone` → `phone_mobile`
**Files**: `twopayment.php` → buyer payload building

### [2025-11-14] Gross Amount Mismatch (1 cent off)
**Problem**: "Total invoice amount doesn't match" errors
**Root Cause**: PHP floating point vs PrestaShop's stored rounded values
**Fix**: Use `Tools::ps_round()` and 2-cent tolerance constant
**Files**: `twopayment.php` → line item calculations

---

## Checkout Flow Issues

### [2025-10-06] Order Intent Fires Multiple Times
**Problem**: API rate limiting, duplicate processing
**Root Cause**: `updatedPaymentForm` event fires on every checkout change
**Fix**: 800ms cooldown + result caching + `isProcessing` guard
**Files**: `TwoCheckoutManager.js`, `TwoOrderIntent.js`

### [2025-10-06] Payment Option Not Found
**Problem**: Two payment option not detected in custom themes
**Root Cause**: Themes customize payment markup differently
**Fix**: Multiple selector strategies (data-attr → value → action → text)
**Files**: `TwoCheckoutManager.js` → `findTwoPaymentOption()`

---

## Configuration Issues

### [2025-11-14] API Key Typo Migration
**Problem**: Old installations had `PS_TWO_MERACHANT_API_KEY` (typo)
**Root Cause**: Original code had typo in config key
**Fix**: Upgrade script migrates to `PS_TWO_MERCHANT_API_KEY`
**Files**: `upgrade/upgrade-2.2.0.php`

---

## Template for New Entries

```markdown
### [YYYY-MM-DD] Title
**Problem**:
**Root Cause**:
**Fix**:
**Files**:
```
49 changes: 49 additions & 0 deletions .cursor/rules/prestashop.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
alwaysApply: true
---
# Two Payment Module - AI Development Rules

> **Primary context source: `CLAUDE.md` in repository root**
> This file exists for non-Claude AI models. All detailed rules are in CLAUDE.md.

## Quick Rules (see CLAUDE.md for full details)

1. **Read CLAUDE.md first** - Contains all development patterns and rules
2. **Payment safety** - Never deploy untested, always try-catch, never log secrets
3. **Cross-version** - Test on PS 1.7.6+, 8.x, and 9.x
4. **jQuery fallback** - Triple-layer loading + waitForJQuery wrapper
5. **Assets** - Only load on checkout pages, never async
6. **Self-improve** - Update CLAUDE.md and .ai/*.md files when learning

## File References

| Purpose | File |
|---------|------|
| Full AI context | `CLAUDE.md` |
| Architectural decisions | `.ai/decisions.md` |
| Bug fixes & learnings | `.ai/learnings.md` |
| Module documentation | `README.md` |
| Version history | `CHANGELOG.md` |

## Critical Patterns

```php
// Always wrap hooks
public function hookAnyHook($params) {
try {
// logic
} catch (Exception $e) {
PrestaShopLogger::addLog('TwoPayment: ' . $e->getMessage(), 3);
return;
}
}
```

```javascript
// Always wrap JS init
waitForJQuery(function() {
// Safe to use jQuery
});
```

**For complete rules, patterns, and self-improvement protocols, see `CLAUDE.md`.**
36 changes: 36 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Module Tests

on:
push:
pull_request:
workflow_dispatch:

jobs:
test:
name: PHP ${{ matrix.php-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ["8.2", "8.3"]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: none

- name: Syntax check test files
run: |
php -l twopayment.php
php -l controllers/front/payment.php
php -l tests/bootstrap.php
php -l tests/OrderBuilderTest.php
php -l tests/run.php

- name: Run offline test suite
run: php tests/run.php
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ TEST*.xml
.DS_Store
__MACOSX

# IDE - Cursor (optional: can track .cursor/rules/ if sharing rules with team)
# .cursor/

# AI context files - TRACK THESE (valuable for AI and developers)
# .ai/ is tracked intentionally

# Generated by Windows
Thumbs.db

Expand Down
Loading
Loading