From 8d5fa3a68e743ad6c3c9f3de6223b1caab315e57 Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Wed, 22 May 2024 10:56:33 +0400 Subject: [PATCH 1/5] remove validation from addLineItem validation should only take place before persistence --- src/models/Order.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/models/Order.php b/src/models/Order.php index 00cef30..426c3bd 100644 --- a/src/models/Order.php +++ b/src/models/Order.php @@ -192,14 +192,9 @@ public function save(): bool * * @param OrderProduct $orderProduct * @return void - * @throws Exception */ public function addLineItem(OrderProduct $orderProduct): void { - $errors = $orderProduct->validate(); - if (!empty($errors)) { - throw new Exception("Invalid line item: " . json_encode($errors)); - } $this->line_items[] = $orderProduct; } From 49ac371e203644b2960ed4b2517cf3711949f557 Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Wed, 22 May 2024 11:14:50 +0400 Subject: [PATCH 2/5] improve exception message when line item is invalid in save() --- src/models/Order.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/models/Order.php b/src/models/Order.php index 426c3bd..b5008e8 100644 --- a/src/models/Order.php +++ b/src/models/Order.php @@ -122,11 +122,19 @@ public function save(): bool $update_stock_stm = $conn->prepare($query); foreach ($this->line_items as $line_item) { - if (!empty($line_item->validate())) { + $line_item_errors = $line_item->validate(); + + if (!empty($line_item_errors)) { // line item contains invalid attributes $conn->rollBack(); $conn = null; - throw new Exception("Invalid line item:" . json_encode($line_item)); + + $error_message = "Invalid line item:" . json_encode($line_item->toArray()); + $error_message .= " Errors: " . json_encode($line_item_errors); + + throw new Exception( + $error_message + ); } // fetch product corresponding to line item From 248c40ed829517c955902b56c5a25a4adc73e01c Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Wed, 22 May 2024 11:15:15 +0400 Subject: [PATCH 3/5] improve error messages --- src/controllers/Cart.php | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/controllers/Cart.php b/src/controllers/Cart.php index 5f93ec9..aec8d85 100644 --- a/src/controllers/Cart.php +++ b/src/controllers/Cart.php @@ -7,7 +7,6 @@ use Exception; use Steamy\Core\Controller; use Steamy\Core\Utility; -use Steamy\Model\Mailer; use Steamy\Model\Order; use Steamy\Model\OrderProduct; use Steamy\Model\Product; @@ -71,8 +70,6 @@ private function handleInvalidURL(): void private function handleCheckout(): void { - // TODO: write appropriate errors to Cart view instead of sending response code - // check if user is logged in $signed_client = $this->getSignedInClient(); if (!$signed_client) { @@ -110,24 +107,35 @@ private function handleCheckout(): void $new_order->addLineItem($line_item); } - // save order - $success_order = false; + // attempt to save order. An exception will be generated in case of any errors. try { $success_order = $new_order->save(); - http_response_code($success_order ? 201 : 400); } catch (Exception $e) { error_log($e->getMessage()); http_response_code(500); echo json_encode(['error' => $e->getMessage()]); + return; } - // send confirmation email if order was successfully saved - if ($success_order) { - try { - $signed_client->sendOrderConfirmationEmail($new_order); - } catch (Exception $e) { - error_log($e->getMessage()); - } + // if order was unsuccessfully saved without any exceptions generated + if (!$success_order) { + http_response_code(500); + echo json_encode(['error' => "Order could not be saved for an unknown reason."]); + return; + } + + // send confirmation email + try { + $success_mail = $signed_client->sendOrderConfirmationEmail($new_order); + } catch (Exception $e) { + http_response_code(503); + echo json_encode(['error' => "Order was saved but email could not be sent: " . $e->getMessage()]); + return; + } + + if (!$success_mail) { + http_response_code(503); + echo json_encode(['error' => "Order was saved but email could not be sent for an unknown reason."]); } } From 69239d8b8b07c18d34be8f337879cf69ea06579a Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Wed, 22 May 2024 11:48:33 +0400 Subject: [PATCH 4/5] add doc to constructor --- src/models/OrderProduct.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/models/OrderProduct.php b/src/models/OrderProduct.php index 0048327..2c79e13 100644 --- a/src/models/OrderProduct.php +++ b/src/models/OrderProduct.php @@ -20,6 +20,15 @@ class OrderProduct private int $quantity; private float $unit_price; + /** + * Create a new OrderProduct object + * @param int $product_id + * @param string $cup_size + * @param string $milk_type + * @param int $quantity + * @param float|null $unit_price If not set, the default $unit_price is -1. + * @param int|null $order_id If not set, the default $order_id is -1. + */ public function __construct( int $product_id, string $cup_size, From 48b2d7c817119ad0e4f1e4607692bb64cf3f9388 Mon Sep 17 00:00:00 2001 From: creme332 <65414576+creme332@users.noreply.github.com> Date: Wed, 22 May 2024 11:50:01 +0400 Subject: [PATCH 5/5] change order of steps when saving order set order id and unit price of each line item before validating line item --- src/models/Order.php | 53 ++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/models/Order.php b/src/models/Order.php index b5008e8..1448a12 100644 --- a/src/models/Order.php +++ b/src/models/Order.php @@ -122,20 +122,8 @@ public function save(): bool $update_stock_stm = $conn->prepare($query); foreach ($this->line_items as $line_item) { - $line_item_errors = $line_item->validate(); - - if (!empty($line_item_errors)) { - // line item contains invalid attributes - $conn->rollBack(); - $conn = null; - - $error_message = "Invalid line item:" . json_encode($line_item->toArray()); - $error_message .= " Errors: " . json_encode($line_item_errors); - - throw new Exception( - $error_message - ); - } + // set order ID of line item + $line_item->setOrderID($new_order_id); // fetch product corresponding to line item $product = Product::getByID($line_item->getProductID()); @@ -147,6 +135,9 @@ public function save(): bool throw new Exception("Product with ID " . $line_item->getProductID() . " does not exist"); } + // set true unit price of line item + $line_item->setUnitPrice($product->getPrice()); + // get stock level for current product $stock_level = $store->getProductStock($product->getProductID()); @@ -154,15 +145,39 @@ public function save(): bool // store does not have enough stock $conn->rollBack(); $conn = null; + + $error_message = <<< EOL + Store with ID $this->store_id has insufficient stock ($stock_level) for the following line item: + Product ID = {$line_item->getProductID()} and quantity = {$line_item->getQuantity()}. + EOL; + + throw new Exception($error_message); + } + + // validate line item + $line_item_errors = $line_item->validate(); + if (!empty($line_item_errors)) { + // line item contains invalid attributes + $conn->rollBack(); + $conn = null; + + $line_item_info = json_encode($line_item->toArray()); + $line_item_errors = json_encode($line_item_errors); + + $error_message = <<< EOL + Invalid line item: + $line_item_info + + Errors: + $line_item_errors + EOL; + throw new Exception( - "Store with ID " . $this->store_id - . " has insufficient stock for product " . $line_item->getProductID() + $error_message ); } - // insert into order_product table - $line_item->setOrderID($new_order_id); - $line_item->setUnitPrice($product->getPrice()); + // insert line item into order_product table $success = $insert_line_item_stm->execute($line_item->toArray()); if (!$success) {