|
@@ -6,10 +6,16 @@ use ApiPlatform\Laravel\Eloquent\Paginator;
|
|
|
use ApiPlatform\Metadata\Operation;
|
|
use ApiPlatform\Metadata\Operation;
|
|
|
use ApiPlatform\State\ProviderInterface;
|
|
use ApiPlatform\State\ProviderInterface;
|
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
|
|
|
+use Illuminate\Support\Collection;
|
|
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
use Webkul\BagistoApi\Admin\Dto\AdminOrderListDto;
|
|
use Webkul\BagistoApi\Admin\Dto\AdminOrderListDto;
|
|
|
use Webkul\BagistoApi\Admin\Helper\AdminAuthHelper;
|
|
use Webkul\BagistoApi\Admin\Helper\AdminAuthHelper;
|
|
|
use Webkul\BagistoApi\Admin\Models\AdminOrder;
|
|
use Webkul\BagistoApi\Admin\Models\AdminOrder;
|
|
|
|
|
+use Webkul\BagistoApi\Admin\Models\AdminOrderCustomerNote;
|
|
|
|
|
+use Webkul\BagistoApi\Admin\Models\AdminOrderDetailAddress;
|
|
|
|
|
+use Webkul\BagistoApi\Admin\Models\AdminOrderDetailComment;
|
|
|
|
|
+use Webkul\BagistoApi\Admin\Models\AdminOrderDetailInvoice;
|
|
|
use Webkul\BagistoApi\Admin\Models\AdminOrderItemPreview;
|
|
use Webkul\BagistoApi\Admin\Models\AdminOrderItemPreview;
|
|
|
use Webkul\BagistoApi\Admin\State\Concerns\ResolvesAdminDateRange;
|
|
use Webkul\BagistoApi\Admin\State\Concerns\ResolvesAdminDateRange;
|
|
|
use Webkul\BagistoApi\Exception\AuthenticationException;
|
|
use Webkul\BagistoApi\Exception\AuthenticationException;
|
|
@@ -45,8 +51,12 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
|
|
|
|
|
$query = Order::query()->with([
|
|
$query = Order::query()->with([
|
|
|
'items.product.images',
|
|
'items.product.images',
|
|
|
|
|
+ 'items.child',
|
|
|
'addresses',
|
|
'addresses',
|
|
|
'payment',
|
|
'payment',
|
|
|
|
|
+ 'invoices',
|
|
|
|
|
+ 'transactions',
|
|
|
|
|
+ 'comments',
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
$this->applyFilters($query, $args);
|
|
$this->applyFilters($query, $args);
|
|
@@ -56,12 +66,16 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
|
|
|
|
|
$isGraphQL = ! empty($context['graphql_operation_name']);
|
|
$isGraphQL = ! empty($context['graphql_operation_name']);
|
|
|
|
|
|
|
|
- $orders = $query->offset(($page - 1) * $perPage)
|
|
|
|
|
|
|
+ $orderModels = $query->offset(($page - 1) * $perPage)
|
|
|
->limit($perPage)
|
|
->limit($perPage)
|
|
|
- ->get()
|
|
|
|
|
|
|
+ ->get();
|
|
|
|
|
+
|
|
|
|
|
+ $notesByCustomer = $this->customerNotesByCustomer($orderModels);
|
|
|
|
|
+
|
|
|
|
|
+ $orders = $orderModels
|
|
|
->map(fn (Order $order) => $isGraphQL
|
|
->map(fn (Order $order) => $isGraphQL
|
|
|
- ? $this->toAdminOrderEloquent($order)
|
|
|
|
|
- : $this->toAdminOrderDto($order))
|
|
|
|
|
|
|
+ ? $this->toAdminOrderEloquent($order, $notesByCustomer)
|
|
|
|
|
+ : $this->toAdminOrderDto($order, $notesByCustomer))
|
|
|
->all();
|
|
->all();
|
|
|
|
|
|
|
|
return new Paginator(
|
|
return new Paginator(
|
|
@@ -177,8 +191,16 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
/**
|
|
/**
|
|
|
* Map an Order model to the slim AdminOrder row.
|
|
* Map an Order model to the slim AdminOrder row.
|
|
|
*/
|
|
*/
|
|
|
- protected function toAdminOrderEloquent(Order $order): AdminOrder
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param array<int, array<int, array<string, mixed>>> $notesByCustomer
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function toAdminOrderEloquent(Order $order, array $notesByCustomer = []): AdminOrder
|
|
|
{
|
|
{
|
|
|
|
|
+ $currency = $order->order_currency_code;
|
|
|
|
|
+ $notes = $this->notesFor($order, $notesByCustomer);
|
|
|
|
|
+ $insurance = (float) ($order->shipping_insurance_amount ?? 0);
|
|
|
|
|
+ $baseInsurance = (float) ($order->base_shipping_insurance_amount ?? 0);
|
|
|
|
|
+
|
|
|
$model = (new AdminOrder)->forceFill(array_merge($order->getAttributes(), [
|
|
$model = (new AdminOrder)->forceFill(array_merge($order->getAttributes(), [
|
|
|
'id' => (int) $order->id,
|
|
'id' => (int) $order->id,
|
|
|
'increment_id' => $order->increment_id,
|
|
'increment_id' => $order->increment_id,
|
|
@@ -194,34 +216,53 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
'coupon_code' => $order->coupon_code,
|
|
'coupon_code' => $order->coupon_code,
|
|
|
'total_item_count' => $order->total_item_count,
|
|
'total_item_count' => $order->total_item_count,
|
|
|
'total_qty_ordered' => (int) $order->total_qty_ordered,
|
|
'total_qty_ordered' => (int) $order->total_qty_ordered,
|
|
|
- 'order_currency_code' => $order->order_currency_code,
|
|
|
|
|
|
|
+ 'base_currency_code' => $order->base_currency_code,
|
|
|
|
|
+ 'channel_currency_code' => $order->channel_currency_code,
|
|
|
|
|
+ 'order_currency_code' => $currency,
|
|
|
|
|
+ 'transaction_id' => $this->orderTransactionId($order),
|
|
|
|
|
+ 'customer_note' => $notes[0]['note'] ?? null,
|
|
|
|
|
+ 'shipping_insurance_amount' => $insurance,
|
|
|
|
|
+ 'base_shipping_insurance_amount' => $baseInsurance,
|
|
|
|
|
+ 'formatted_shipping_insurance_amount' => $this->safeFormatPrice($insurance, $currency),
|
|
|
'grand_total' => (float) $order->grand_total,
|
|
'grand_total' => (float) $order->grand_total,
|
|
|
'base_grand_total' => (float) $order->base_grand_total,
|
|
'base_grand_total' => (float) $order->base_grand_total,
|
|
|
- 'formatted_grand_total' => $this->safeFormatPrice($order->grand_total, $order->order_currency_code),
|
|
|
|
|
|
|
+ 'formatted_grand_total' => $this->safeFormatPrice($order->grand_total, $currency),
|
|
|
'location' => $this->billingLocation($order),
|
|
'location' => $this->billingLocation($order),
|
|
|
'created_at' => (string) $order->created_at,
|
|
'created_at' => (string) $order->created_at,
|
|
|
'updated_at' => (string) $order->updated_at,
|
|
'updated_at' => (string) $order->updated_at,
|
|
|
]));
|
|
]));
|
|
|
|
|
|
|
|
- $items = $order->items->map(function ($orderItem) {
|
|
|
|
|
- $preview = $this->toItemPreview($orderItem);
|
|
|
|
|
-
|
|
|
|
|
- return (new AdminOrderItemPreview)->forceFill([
|
|
|
|
|
- 'id' => $preview['id'],
|
|
|
|
|
- 'sku' => $preview['sku'],
|
|
|
|
|
- 'name' => $preview['name'],
|
|
|
|
|
- 'qty_ordered' => $preview['qtyOrdered'],
|
|
|
|
|
- 'product_image' => $preview['productImage'],
|
|
|
|
|
- ]);
|
|
|
|
|
- })->values();
|
|
|
|
|
-
|
|
|
|
|
- $model->setRelation('items', $items);
|
|
|
|
|
|
|
+ $model->setRelation('items', $order->items->map(
|
|
|
|
|
+ fn ($orderItem) => $this->toItemModel($orderItem, $currency)
|
|
|
|
|
+ )->values());
|
|
|
|
|
+ $model->setRelation('addresses', $this->addressModels($order));
|
|
|
|
|
+ $model->setRelation('invoices', $order->invoices->map(
|
|
|
|
|
+ fn ($invoice) => $this->toInvoiceModel($invoice, $order)
|
|
|
|
|
+ )->values());
|
|
|
|
|
+ $model->setRelation('comments', $this->commentModels($order));
|
|
|
|
|
+ $model->setRelation('customerNotes', collect($notes)->map(
|
|
|
|
|
+ fn (array $note) => (new AdminOrderCustomerNote)->forceFill([
|
|
|
|
|
+ 'id' => $note['id'],
|
|
|
|
|
+ 'customer_id' => $note['customerId'],
|
|
|
|
|
+ 'note' => $note['note'],
|
|
|
|
|
+ 'customer_notified' => $note['customerNotified'],
|
|
|
|
|
+ 'created_at' => $note['createdAt'],
|
|
|
|
|
+ ])
|
|
|
|
|
+ )->values());
|
|
|
|
|
|
|
|
return $model;
|
|
return $model;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- protected function toAdminOrderDto(Order $order): AdminOrderListDto
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param array<int, array<int, array<string, mixed>>> $notesByCustomer
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function toAdminOrderDto(Order $order, array $notesByCustomer = []): AdminOrderListDto
|
|
|
{
|
|
{
|
|
|
|
|
+ $currency = $order->order_currency_code;
|
|
|
|
|
+ $notes = $this->notesFor($order, $notesByCustomer);
|
|
|
|
|
+ $insurance = (float) ($order->shipping_insurance_amount ?? 0);
|
|
|
|
|
+ $baseInsurance = (float) ($order->base_shipping_insurance_amount ?? 0);
|
|
|
|
|
+
|
|
|
$row = new AdminOrderListDto;
|
|
$row = new AdminOrderListDto;
|
|
|
|
|
|
|
|
$row->id = $order->id;
|
|
$row->id = $order->id;
|
|
@@ -238,14 +279,32 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
$row->coupon_code = $order->coupon_code;
|
|
$row->coupon_code = $order->coupon_code;
|
|
|
$row->total_item_count = $order->total_item_count;
|
|
$row->total_item_count = $order->total_item_count;
|
|
|
$row->total_qty_ordered = (int) $order->total_qty_ordered;
|
|
$row->total_qty_ordered = (int) $order->total_qty_ordered;
|
|
|
- $row->order_currency_code = $order->order_currency_code;
|
|
|
|
|
|
|
+ $row->base_currency_code = $order->base_currency_code;
|
|
|
|
|
+ $row->channel_currency_code = $order->channel_currency_code;
|
|
|
|
|
+ $row->order_currency_code = $currency;
|
|
|
|
|
+ $row->transaction_id = $this->orderTransactionId($order);
|
|
|
|
|
+ $row->customer_note = $notes[0]['note'] ?? null;
|
|
|
|
|
+ $row->shipping_insurance_amount = $insurance;
|
|
|
|
|
+ $row->base_shipping_insurance_amount = $baseInsurance;
|
|
|
|
|
+ $row->formatted_shipping_insurance_amount = $this->safeFormatPrice($insurance, $currency);
|
|
|
$row->grand_total = (float) $order->grand_total;
|
|
$row->grand_total = (float) $order->grand_total;
|
|
|
$row->base_grand_total = (float) $order->base_grand_total;
|
|
$row->base_grand_total = (float) $order->base_grand_total;
|
|
|
- $row->formatted_grand_total = $this->safeFormatPrice($order->grand_total, $order->order_currency_code);
|
|
|
|
|
|
|
+ $row->formatted_grand_total = $this->safeFormatPrice($order->grand_total, $currency);
|
|
|
$row->location = $this->billingLocation($order);
|
|
$row->location = $this->billingLocation($order);
|
|
|
$row->created_at = (string) $order->created_at;
|
|
$row->created_at = (string) $order->created_at;
|
|
|
$row->updated_at = (string) $order->updated_at;
|
|
$row->updated_at = (string) $order->updated_at;
|
|
|
- $row->items = $order->items->map(fn ($orderItem) => $this->toItemPreview($orderItem))->all();
|
|
|
|
|
|
|
+ $row->addresses = array_values(array_filter([
|
|
|
|
|
+ $this->toAddress($order->billing_address),
|
|
|
|
|
+ $this->toAddress($order->shipping_address),
|
|
|
|
|
+ ]));
|
|
|
|
|
+ $row->invoices = $order->invoices
|
|
|
|
|
+ ->map(fn ($invoice) => $this->toInvoice($invoice, $order, $currency))
|
|
|
|
|
+ ->all();
|
|
|
|
|
+ $row->customer_notes = $notes;
|
|
|
|
|
+ $row->comments = $this->toComments($order);
|
|
|
|
|
+ $row->items = $order->items
|
|
|
|
|
+ ->map(fn ($orderItem) => $this->toItemPreview($orderItem, $currency))
|
|
|
|
|
+ ->all();
|
|
|
|
|
|
|
|
return $row;
|
|
return $row;
|
|
|
}
|
|
}
|
|
@@ -264,9 +323,11 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- protected function toItemPreview($orderItem): array
|
|
|
|
|
|
|
+ protected function toItemPreview($orderItem, ?string $currency): array
|
|
|
{
|
|
{
|
|
|
$image = $orderItem->product?->images?->first();
|
|
$image = $orderItem->product?->images?->first();
|
|
|
|
|
+ $additional = is_array($orderItem->additional) ? $orderItem->additional : null;
|
|
|
|
|
+ $childName = $orderItem->relationLoaded('child') ? $orderItem->child?->name : null;
|
|
|
|
|
|
|
|
return [
|
|
return [
|
|
|
'id' => $orderItem->id,
|
|
'id' => $orderItem->id,
|
|
@@ -274,9 +335,248 @@ class OrderCollectionProvider implements ProviderInterface
|
|
|
'name' => $orderItem->name,
|
|
'name' => $orderItem->name,
|
|
|
'qtyOrdered' => (int) $orderItem->qty_ordered,
|
|
'qtyOrdered' => (int) $orderItem->qty_ordered,
|
|
|
'productImage' => $image ? Storage::url($image->path) : null,
|
|
'productImage' => $image ? Storage::url($image->path) : null,
|
|
|
|
|
+ 'productId' => $orderItem->product_id !== null ? (int) $orderItem->product_id : null,
|
|
|
|
|
+ 'variantName' => AdminOrderItemPreview::variantNameFrom($additional, $childName),
|
|
|
|
|
+ 'variantTitle' => AdminOrderItemPreview::variantTitleFrom($additional),
|
|
|
|
|
+ 'price' => (float) $orderItem->price,
|
|
|
|
|
+ 'basePrice' => (float) $orderItem->base_price,
|
|
|
|
|
+ 'formattedPrice' => $this->safeFormatPrice($orderItem->price, $currency),
|
|
|
|
|
+ 'total' => (float) $orderItem->total,
|
|
|
|
|
+ 'baseTotal' => (float) $orderItem->base_total,
|
|
|
|
|
+ 'formattedTotal' => $this->safeFormatPrice($orderItem->total, $currency),
|
|
|
|
|
+ 'taxAmount' => (float) $orderItem->tax_amount,
|
|
|
|
|
+ 'formattedTaxAmount' => $this->safeFormatPrice($orderItem->tax_amount, $currency),
|
|
|
|
|
+ 'discountAmount' => (float) $orderItem->discount_amount,
|
|
|
|
|
+ 'formattedDiscountAmount' => $this->safeFormatPrice($orderItem->discount_amount, $currency),
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function toItemModel($orderItem, ?string $currency): AdminOrderItemPreview
|
|
|
|
|
+ {
|
|
|
|
|
+ $preview = $this->toItemPreview($orderItem, $currency);
|
|
|
|
|
+
|
|
|
|
|
+ return (new AdminOrderItemPreview)->forceFill([
|
|
|
|
|
+ 'id' => $preview['id'],
|
|
|
|
|
+ 'sku' => $preview['sku'],
|
|
|
|
|
+ 'name' => $preview['name'],
|
|
|
|
|
+ 'qty_ordered' => $preview['qtyOrdered'],
|
|
|
|
|
+ 'product_image' => $preview['productImage'],
|
|
|
|
|
+ 'product_id' => $preview['productId'],
|
|
|
|
|
+ 'variant_name' => $preview['variantName'],
|
|
|
|
|
+ 'variant_title' => $preview['variantTitle'],
|
|
|
|
|
+ 'price' => $preview['price'],
|
|
|
|
|
+ 'base_price' => $preview['basePrice'],
|
|
|
|
|
+ 'formatted_price' => $preview['formattedPrice'],
|
|
|
|
|
+ 'total' => $preview['total'],
|
|
|
|
|
+ 'base_total' => $preview['baseTotal'],
|
|
|
|
|
+ 'formatted_total' => $preview['formattedTotal'],
|
|
|
|
|
+ 'tax_amount' => $preview['taxAmount'],
|
|
|
|
|
+ 'formatted_tax_amount' => $preview['formattedTaxAmount'],
|
|
|
|
|
+ 'discount_amount' => $preview['discountAmount'],
|
|
|
|
|
+ 'formatted_discount_amount' => $preview['formattedDiscountAmount'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function toAddress($address): ?array
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! $address) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'id' => (int) $address->id,
|
|
|
|
|
+ 'addressType' => $address->address_type,
|
|
|
|
|
+ 'firstName' => $address->first_name,
|
|
|
|
|
+ 'lastName' => $address->last_name,
|
|
|
|
|
+ 'companyName' => $address->company_name,
|
|
|
|
|
+ 'vatId' => $address->vat_id,
|
|
|
|
|
+ 'address' => $address->address,
|
|
|
|
|
+ 'city' => $address->city,
|
|
|
|
|
+ 'state' => $address->state,
|
|
|
|
|
+ 'country' => $address->country,
|
|
|
|
|
+ 'postcode' => $address->postcode,
|
|
|
|
|
+ 'email' => $address->email,
|
|
|
|
|
+ 'phone' => $address->phone,
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ protected function addressModels(Order $order): Collection
|
|
|
|
|
+ {
|
|
|
|
|
+ return collect(array_filter([
|
|
|
|
|
+ $order->billing_address,
|
|
|
|
|
+ $order->shipping_address,
|
|
|
|
|
+ ]))->map(function ($address) {
|
|
|
|
|
+ return (new AdminOrderDetailAddress)->forceFill($address->getAttributes());
|
|
|
|
|
+ })->values();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function toInvoice($invoice, Order $order, ?string $currency): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $insurance = (float) ($invoice->shipping_insurance_amount ?? 0);
|
|
|
|
|
+ $baseInsurance = (float) ($invoice->base_shipping_insurance_amount ?? 0);
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'id' => (int) $invoice->id,
|
|
|
|
|
+ 'incrementId' => $invoice->increment_id,
|
|
|
|
|
+ 'state' => $invoice->state,
|
|
|
|
|
+ 'emailSent' => (bool) $invoice->email_sent,
|
|
|
|
|
+ 'totalQty' => (int) $invoice->total_qty,
|
|
|
|
|
+ 'subTotal' => (float) $invoice->sub_total,
|
|
|
|
|
+ 'formattedSubTotal' => $this->safeFormatPrice($invoice->sub_total, $currency),
|
|
|
|
|
+ 'grandTotal' => (float) $invoice->grand_total,
|
|
|
|
|
+ 'formattedGrandTotal' => $this->safeFormatPrice($invoice->grand_total, $currency),
|
|
|
|
|
+ 'taxAmount' => (float) $invoice->tax_amount,
|
|
|
|
|
+ 'discountAmount' => (float) $invoice->discount_amount,
|
|
|
|
|
+ 'shippingAmount' => (float) $invoice->shipping_amount,
|
|
|
|
|
+ 'shippingInsuranceAmount' => $insurance,
|
|
|
|
|
+ 'baseShippingInsuranceAmount' => $baseInsurance,
|
|
|
|
|
+ 'transactionId' => $this->invoiceTransactionId($invoice, $order),
|
|
|
|
|
+ 'createdAt' => (string) $invoice->created_at,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function toInvoiceModel($invoice, Order $order): AdminOrderDetailInvoice
|
|
|
|
|
+ {
|
|
|
|
|
+ return (new AdminOrderDetailInvoice)->forceFill(array_merge($invoice->getAttributes(), [
|
|
|
|
|
+ 'transaction_id' => $this->invoiceTransactionId($invoice, $order),
|
|
|
|
|
+ 'shipping_insurance_amount' => (float) ($invoice->shipping_insurance_amount ?? 0),
|
|
|
|
|
+ 'base_shipping_insurance_amount' => (float) ($invoice->base_shipping_insurance_amount ?? 0),
|
|
|
|
|
+ ]));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @return array<int, array<string, mixed>>
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function toComments(Order $order): array
|
|
|
|
|
+ {
|
|
|
|
|
+ return $order->comments
|
|
|
|
|
+ ->sortByDesc('id')
|
|
|
|
|
+ ->map(fn ($comment) => [
|
|
|
|
|
+ 'id' => (int) $comment->id,
|
|
|
|
|
+ 'comment' => $comment->comment,
|
|
|
|
|
+ 'customerNotified' => (bool) $comment->customer_notified,
|
|
|
|
|
+ 'createdAt' => (string) $comment->created_at,
|
|
|
|
|
+ ])
|
|
|
|
|
+ ->values()
|
|
|
|
|
+ ->all();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function commentModels(Order $order): Collection
|
|
|
|
|
+ {
|
|
|
|
|
+ return $order->comments
|
|
|
|
|
+ ->sortByDesc('id')
|
|
|
|
|
+ ->map(fn ($comment) => (new AdminOrderDetailComment)->forceFill([
|
|
|
|
|
+ 'id' => (int) $comment->id,
|
|
|
|
|
+ 'comment' => $comment->comment,
|
|
|
|
|
+ 'customer_notified' => (bool) $comment->customer_notified,
|
|
|
|
|
+ 'created_at' => $comment->created_at,
|
|
|
|
|
+ ]))
|
|
|
|
|
+ ->values();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Gateway capture id for the order. Payment additional is written on
|
|
|
|
|
+ * capture (`transaction_id`) and by the Magento import (`last_trans_id`);
|
|
|
|
|
+ * invoices and `order_transactions` are the fallback.
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function orderTransactionId(Order $order): ?string
|
|
|
|
|
+ {
|
|
|
|
|
+ $additional = $order->payment?->additional;
|
|
|
|
|
+
|
|
|
|
|
+ if (is_array($additional)) {
|
|
|
|
|
+ foreach (['transaction_id', 'last_trans_id'] as $key) {
|
|
|
|
|
+ $value = trim((string) ($additional[$key] ?? ''));
|
|
|
|
|
+
|
|
|
|
|
+ if ($value !== '') {
|
|
|
|
|
+ return $value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $paypal = $additional['paypal']['Last Transaction ID'] ?? null;
|
|
|
|
|
+
|
|
|
|
|
+ if (is_string($paypal) && trim($paypal) !== '') {
|
|
|
|
|
+ return trim($paypal);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($order->invoices as $invoice) {
|
|
|
|
|
+ $id = $this->invoiceTransactionId($invoice, $order);
|
|
|
|
|
+
|
|
|
|
|
+ if ($id !== null) {
|
|
|
|
|
+ return $id;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $txn = $order->transactions->first();
|
|
|
|
|
+
|
|
|
|
|
+ if ($txn && ! empty($txn->transaction_id)) {
|
|
|
|
|
+ return (string) $txn->transaction_id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function invoiceTransactionId($invoice, Order $order): ?string
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! empty($invoice->transaction_id)) {
|
|
|
|
|
+ return (string) $invoice->transaction_id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $linked = $order->transactions->first(
|
|
|
|
|
+ fn ($txn) => (int) $txn->invoice_id === (int) $invoice->id
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if ($linked && ! empty($linked->transaction_id)) {
|
|
|
|
|
+ return (string) $linked->transaction_id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Customer profile notes, newest first, keyed by customer id.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param Collection<int, Order> $orders
|
|
|
|
|
+ * @return array<int, array<int, array<string, mixed>>>
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function customerNotesByCustomer(Collection $orders): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $ids = $orders->pluck('customer_id')->filter()->map(fn ($id) => (int) $id)->unique()->values();
|
|
|
|
|
+
|
|
|
|
|
+ if ($ids->isEmpty()) {
|
|
|
|
|
+ return [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $grouped = [];
|
|
|
|
|
+
|
|
|
|
|
+ foreach (DB::table('customer_notes')->whereIn('customer_id', $ids->all())->orderByDesc('id')->get() as $row) {
|
|
|
|
|
+ $grouped[(int) $row->customer_id][] = [
|
|
|
|
|
+ 'id' => (int) $row->id,
|
|
|
|
|
+ 'note' => $row->note,
|
|
|
|
|
+ 'customerId' => (int) $row->customer_id,
|
|
|
|
|
+ 'customerNotified' => (bool) $row->customer_notified,
|
|
|
|
|
+ 'createdAt' => $row->created_at !== null ? (string) $row->created_at : null,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $grouped;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @param array<int, array<int, array<string, mixed>>> $notesByCustomer
|
|
|
|
|
+ * @return array<int, array<string, mixed>>
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function notesFor(Order $order, array $notesByCustomer): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $customerId = (int) ($order->customer_id ?? 0);
|
|
|
|
|
+
|
|
|
|
|
+ if ($customerId <= 0) {
|
|
|
|
|
+ return [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $notesByCustomer[$customerId] ?? [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Resolve the payment-method display title from core config.
|
|
* Resolve the payment-method display title from core config.
|
|
|
*/
|
|
*/
|