Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/pod.git

Fixes payment currency conversion

AuthorDave Jarvis <email>
Date2026-01-26 22:37:55 GMT-0800
Commitf3ef7e6fc66b6e09898fca0a4495cd7a0ff163da
Parent0b667ef
Currency.php
return str_replace( $placeholder, $this->value, $text );
}
+
+ public function toString(): string {
+ return $this->value;
+ }
+
+ public static function fromCountry( string $countryCode ): Currency {
+ return match( strtoupper( $countryCode ) ) {
+ 'AU' => self::AUD,
+ 'CA' => self::CAD,
+ 'GB', 'UK' => self::GBP,
+ 'US' => self::USD,
+ 'AT', 'BE', 'CY', 'EE', 'FI', 'FR', 'DE', 'GR', 'IE', 'IT',
+ 'LV', 'LT', 'LU', 'MT', 'NL', 'PT', 'SK', 'SI', 'ES' => self::EUR,
+ default => self::CAD,
+ };
+ }
}
ExchangeRate.php
private function expired( string $cache ): bool {
- return !file_exists( $cache )
- || ( time() - filemtime( $cache ) ) > $this->cacheLifetime;
+ return
+ !file_exists( $cache ) ||
+ (time() - filemtime( $cache )) > $this->cacheLifetime;
}
private function fetch( string $source, string $cache ): void {
$response = @file_get_contents( $source );
if( is_string( $response ) ) {
$payload = json_decode( $response, true );
- if( isset( $payload['rates'] ) && isset( $payload['base'] ) ) {
- $this->parse( $payload );
+ if( isset( $payload['rates'] ) ) {
+ $this->rates = $payload['rates'];
+ $this->rates[ 'CAD' ] = 1.0;
if( $source !== $cache ) {
file_put_contents( $cache, json_encode( $payload ) );
}
}
}
- }
-
- private function parse( array $payload ): void {
- $this->rates = $payload['rates'];
- $this->base = $payload['base'];
}
private function rateFor( Currency $currency ): float {
- $code = $currency->value;
-
- if( $code === $this->base ) {
- return 1.0;
- }
-
- return $this->rates[$code]
- ?? $this->rateFor( Currency::from( $this->base ) );
+ return (float)$this->rates[ $currency->toString() ];
}
}
Money.php
private Currency $currency;
- public function __construct( float $amount, Currency $currency ) {
+ public function __construct(
+ float $amount,
+ Currency $currency = Currency::CAD
+ ) {
$this->amount = $amount;
$this->currency = $currency;
}
public function convert( ExchangeRate $forex, Currency $target ): Money {
- $rate = $forex->rate( $this->currency, $target );
- return new Money( $this->amount * $rate, $target );
+ $rate = (float)$forex->rate( $this->currency, $target );
+ return new Money( (float)($this->amount * $rate), $target );
}
Order.php
<?php
+require_once 'Currency.php';
+require_once 'ExchangeRate.php';
+require_once 'Money.php';
+
class Order {
private $summary = [];
public function process( array $response, int $statusCode ) {
if( $statusCode === 201 ) {
- $this->processSuccess( $response );
+ $this->processResponse( $response );
} else {
$this->processError( $response, $statusCode );
}
}
- protected function processSuccess( array $response ): void {
- $this->summary = $response;
- $this->renderMethod = 'renderSummary';
- $this->success = true;
+ protected function processResponse( array $response ): void {
+ $errorDetail = '';
+ $lineItem = $response['line_item_costs'][0] ?? null;
+
+ if( !isset( $lineItem['total_cost_excl_tax'] ) ||
+ !isset( $response['total_cost_incl_tax'] ) ||
+ !isset( $response['shipping_address'] ) ) {
+ $errorDetail = 'Invalid order data received from server.';
+ } else {
+ $bookPrice = (float)( $lineItem['total_cost_excl_tax'] );
+
+ if( $bookPrice <= 0 ) {
+ $errorDetail = 'Invalid book price received.';
+ }
+ }
+
+ if( empty( $errorDetail ) ) {
+ $this->summary = $response;
+ $this->renderMethod = 'renderSummary';
+ $this->success = true;
+ } else {
+ $this->processError( ['detail' => $errorDetail], 500 );
+ }
}
private function renderSummary() {
+ $EXCLUDING = "total_cost_excl_tax";
+ $config = new Configuration();
+ $forex = $config->createExchangeRate( Currency::CAD );
+
$address = $this->summary[ 'shipping_address' ];
- $currency = $this->escape( $this->summary[ 'currency' ] );
+ $target = Currency::fromCountry( $address['country'] ?? 'CA' );
+
+ $price = new Money( $this->summary['line_item_costs'][0][$EXCLUDING] );
+ $shipping = new Money( $this->summary['shipping_cost'][$EXCLUDING] );
+ $fulfillment = new Money( $this->summary['fulfillment_cost'][$EXCLUDING] );
+ $taxes = new Money( $this->summary['total_tax'] );
+ $total = new Money( $this->summary['total_cost_incl_tax'] );
+
+ $price = $forex->convert( $price, $target );
+ $shipping = $forex->convert( $shipping, $target );
+ $fulfillment = $forex->convert( $fulfillment, $target );
+ $taxes = $forex->convert( $taxes, $target );
+ $total = $forex->convert( $total, $target );
?>
<section>
<tr>
<td>Book price</td>
- <td><?= $this->escape( $this->summary[ 'line_item_costs' ][ 0 ]
- [ 'total_cost_excl_tax' ] ) ?> <?= $currency ?></td>
+ <td><?= $price->render(); ?></td>
</tr>
<tr>
<td>Shipping</td>
- <td><?= $this->escape( $this->summary[ 'shipping_cost' ]
- [ 'total_cost_excl_tax' ] ) ?> <?= $currency ?></td>
+ <td><?= $shipping->render(); ?></td>
+ </tr>
+ <tr>
+ <td>Fulfillment</td>
+ <td><?= $fulfillment->render(); ?></td>
</tr>
<tr>
<td>Taxes</td>
- <td><?= $this->escape( $this->summary[ 'total_tax' ] ) ?>
- <?= $currency ?></td>
+ <td><?= $taxes->render(); ?></td>
</tr>
<tr>
<td><strong>Amount due</strong></td>
- <td><strong><?= $this->escape(
- $this->summary[ 'total_cost_incl_tax' ] ) ?>
- <?= $currency ?></strong></td>
+ <td><strong><?= $total->render(); ?></strong></td>
</tr>
</table>
tests/TestableOrder.php
private bool $successful = false;
- protected function processSuccess( array $response ): void {
+ protected function processResponse( array $response ): void {
$this->successful = true;
- parent::processSuccess( $response );
+ parent::processResponse( $response );
}
Delta84 lines added, 37 lines removed, 47-line increase