send_count++; } } } if (!class_exists('OrdersAutoWashCertificateCompletionDouble')) { class OrdersAutoWashCertificateCompletionDouble extends orders_o { public bool $containsWashCertificate = false; public bool $washCertificateAttached = false; /** @var array */ public array $generatedCertificates = []; public ?order_bookings_o $linkedBooking = null; public function __construct() { $this->id = -1; $this->customer_id = new object_property('orders', -1, 'customer_id', 'int', true); $this->cashier_id = new object_property('orders', -1, 'cashier_id', 'int', true); $this->reference = new object_property('orders', -1, 'reference', 'string', false); $this->notes = new object_property('orders', -1, 'notes', 'string', false); $this->department_id = new object_property('orders', -1, 'department_id', 'int', true); $this->reg_1 = new object_property('orders', -1, 'reg_1', 'string', false); $this->reg_2 = new object_property('orders', -1, 'reg_2', 'string', false); $this->reg_3 = new object_property('orders', -1, 'reg_3', 'string', false); $this->created_at = new object_property('orders', -1, 'created_at', 'timestamp', false); $this->include_in_invoice = new object_property('orders', -1, 'include_in_invoice', 'bool', false); $this->completed_at = new object_property('orders', -1, 'completed_at', 'timestamp', false); $this->deleted_at = new object_property('orders', -1, 'deleted_at', 'timestamp', false); $this->invoice_collection_id = new object_property('orders', -1, 'invoice_collection_id', 'int', false); $this->booking_id = new object_property('orders', -1, 'booking_id', 'int', false); $this->wash_id = new object_property('orders', -1, 'wash_id', 'string', false); $this->lane = new object_property('orders', -1, 'lane', 'string', false); $this->po = new object_property('orders', -1, 'po', 'string', false); $this->safety_seal = new object_property('orders', -1, 'safety_seal', 'string', false); $this->using_hand_held = new object_property('orders', -1, 'using_hand_held', 'bool', false); } public function objectChanged(): void { } protected function resolveDepartmentIncludedInInvoicing(): bool { return true; } public function isPendingHandheld(): bool { return false; } public function containsWashCertificateItem(): bool { return $this->containsWashCertificate; } public function hasWashCertificateAttached(): bool { return $this->washCertificateAttached; } public function generateWashCertificate(string|null $safety_seal = null, string|null $operator = null, $date = null): void { if ($this->washCertificateAttached) { return; } $this->generatedCertificates[] = [ 'seal_number' => self::normalizeSafetySealValue($safety_seal), 'operator' => $operator, 'date' => $date, ]; $this->washCertificateAttached = true; } public function getOrderBooking(): order_bookings_o|null { return $this->linkedBooking; } } } it('auto-attaches a wash certificate on order completion when a wash certificate item is present', function (): void { $booking = new OrdersAutoWashCertificateLinkedBookingDouble(); $order = new OrdersAutoWashCertificateCompletionDouble(); $order->containsWashCertificate = true; $order->booking_id->set(123); $order->linkedBooking = $booking; $order->safety_seal->set('SEAL-41'); $order->markAsCompleted('Operator One'); expect($order->completed_at->value())->not->toBeNull(); expect($order->generatedCertificates)->toHaveCount(1); expect($order->generatedCertificates[0])->toMatchArray([ 'seal_number' => 'SEAL-41', 'operator' => 'Operator One', ]); expect($booking->send_count)->toBe(1); }); it('keeps order completion idempotent when a wash certificate is already attached', function (): void { $booking = new OrdersAutoWashCertificateLinkedBookingDouble(); $order = new OrdersAutoWashCertificateCompletionDouble(); $order->containsWashCertificate = true; $order->washCertificateAttached = true; $order->booking_id->set(456); $order->linkedBooking = $booking; $order->markAsCompleted('Operator Two'); expect($order->generatedCertificates)->toBe([]); expect($booking->send_count)->toBe(0); }); it('allows blank safety seal values when auto-attaching a wash certificate on completion', function (): void { $order = new OrdersAutoWashCertificateCompletionDouble(); $order->containsWashCertificate = true; $order->safety_seal->set(null); $order->markAsCompleted('Operator Three'); expect($order->generatedCertificates)->toHaveCount(1); expect($order->generatedCertificates[0]['seal_number'])->toBeNull(); });