PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / api / Resource / OrderItemResource.php

OrderItemResource.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at api/Resource/OrderItemResource.php

365 lines 17.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\Api\Resource;
4
5 use FluentCart\App\App;
6 use FluentCart\App\Helpers\AttributeHelper;
7 use FluentCart\App\Models\OrderItem;
8 use FluentCart\App\Models\ProductVariation;
9 use FluentCart\Framework\Database\Orm\Builder;
10 use FluentCart\Framework\Support\Arr;
11 use FluentCart\Framework\Support\Collection;
12 use FluentCart\Framework\Support\DateTime;
13
14 class OrderItemResource extends BaseResourceApi
15 {
16
17 public static function getQuery(): Builder
18 {
19 return OrderItem::query();
20 }
21
22 public static function get(array $params = [])
23 {
24
25 }
26
27 /**
28 * Find and retrieve order items based on the order ID.
29 *
30 * @param int $id Required. The ID of the order to find and retrieve.
31 * @param array $params Optional. Additional parameters for finding order items.
32 * [
33 * // Include optional parameters, if any.
34 * ]
35 *
36 */
37 public static function find($id, $params = [])
38 {
39 return static::getQuery()->where('order_id', $id)->get()->toArray();
40 }
41
42 /**
43 * Create order items with the provided data.
44 *
45 * This function creates order items based on the provided data.
46 * It also dispatches events related to order creation and stock changes.
47 *
48 * @param array $data Required. Array containing the necessary parameters
49 * $data => (array) Required. Array of order item details.
50 * [
51 * 'order_id' => (int) The ID of the order to which the item belongs.
52 * 'post_id' => (int) The product ID associated with the order item.
53 * 'object_id' => (int) The variation ID of the order item.
54 * 'thumbnail' => (string) The URL of the thumbnail of order item.
55 * 'price' => (float) The price of the item.
56 * 'title' => (string) The name of the item.
57 * 'quantity' => (int) The quantity of the item.
58 * 'fulfillment_type' => (string) Type (e.g., 'physical', 'digital').
59 * 'stockStatus' => (string) (e.g., 'in-stock'|'out-of-stock').
60 * 'stock' => (int) The current stock quantity.
61 * 'tax_amount' => (float) The tax amount for the item.
62 * 'discount_total' => (float) The total discount amount for the item.
63 * 'total' => (float) The total amount for the item.
64 * 'line_total' => (float) The total amount for the line
65 * ]
66 * @param array $params Optional. Additional parameters for order item creation.
67 * [
68 * // Include optional parameters, if any.
69 * ]
70 *
71 */
72 public static function create($data, $params = [])
73 {
74 $isCreated = static::getQuery()->insert($data);
75
76 if ($isCreated) {
77 return static::makeSuccessResponse(
78 $isCreated,
79 __('Order items created.', 'fluent-cart')
80 );
81 }
82
83 return static::makeErrorResponse([
84 ['code' => 400, 'message' => __('Order items failed to create!', 'fluent-cart')]
85 ]);
86 }
87
88 /**
89 * Update order items with the provided data.
90 *
91 * This function creates order items based on the provided data.
92 * It also dispatches events related to order creation and stock changes.
93 *
94 * @param array $data Required. Array containing the necessary parameters
95 * $data => (array) Required. Array of order item details.
96 * [
97 * 'id' => (int) The id for the order item.
98 * 'order_id' => (int) The ID of the order to which the item belongs.
99 * 'post_id' => (int) The product ID associated with the order item.
100 * 'object_id' => (int) The variation ID of the order item.
101 * 'thumbnail' => (string) The URL of the thumbnail of order item.
102 * 'price' => (float) The price of the item.
103 * 'title' => (string) The name of the item.
104 * 'quantity' => (int) The quantity of the item.
105 * 'fulfillment_type' => (string) Type (e.g., 'physical', 'digital').
106 * 'stockStatus' => (string) (e.g., 'in-stock'|'out-of-stock').
107 * 'stock' => (int) The current stock quantity.
108 * 'tax_amount' => (float) The tax amount for the item.
109 * 'discount_total' => (float) The total discount amount for the item.
110 * 'total' => (float) The total amount for the item.
111 * 'line_total' => (float) The total amount for the line
112 * ]
113 * @param int $id Required. The id of the order item to update.
114 * @param array $params Optional. Additional parameters for order item creation.
115 * [
116 * // Include optional parameters, if any.
117 * ]
118 *
119 */
120 public static function update($data, $id, $params = [])
121 {
122 $isUpdate = static::getQuery()->batchUpdate($data);
123
124 if ($isUpdate) {
125 return static::makeSuccessResponse(
126 $isUpdate,
127 __('Order items updated.', 'fluent-cart')
128 );
129 }
130
131 return static::makeErrorResponse([
132 ['code' => 400, 'message' => __('Order items failed to update!', 'fluent-cart')]
133 ]);
134 }
135
136 public static function delete($id, $params = [])
137 {
138
139 }
140
141 /**
142 * Create or Update order items with the provided data.
143 *
144 * This function creates or updates order items based on the provided data.
145 *
146 * @param array $data Required. Array containing the necessary parameters
147 * $order => (array) Required. Array of order details.
148 * [
149 * 'id' => (int) The id for the order.
150 * 'status' => (string) The current status of the order
151 * 'parent_id' => (int) The parent order ID, if applicable.
152 * 'invoice_no' => (string) The order number assigned to the order.
153 * 'receipt_number' => (int) The sequential order number for using in invoice
154 * 'fulfillment_type' => (string) (e.g., 'virtual', 'physical', etc.).
155 * 'type' => (string) Type (e.g., 'sale', 'refund', etc.).
156 * 'customer_id' => (int) The ID of the customer associated with the order.
157 * 'payment_method' => (string) The payment method used for the order.
158 * 'payment_method_title' => (string) The title of the payment method.
159 * 'currency' => (string) The currency used for the order (e.g., 'BDT').
160 * 'subtotal' => (float) The subtotal amount of the order.
161 * 'discount_tax' => (float) The tax amount on discounts.
162 * 'discount_total' => (float) The total discount amount for the order.
163 * 'shipping_tax' => (float) The tax amount on shipping.
164 * 'shipping_total' => (float) The total shipping amount for the order.
165 * 'tax_total' => (float) The total tax amount for the order.
166 * 'total_amount' => (float) The total amount for the order.
167 * 'total_paid' => (float) The total amount paid for the order.
168 * 'rate' => (float) The exchange rate used for currency conversion.
169 * 'note' => (string) Additional notes or comments for the order.
170 * 'ip_address' => (string) The IP address associated with the order.
171 * 'completed_at' => (string|null) date-time order completed|null
172 * 'refunded_at' => (string|null) date-time the order was refunded|null
173 * 'uuid' => (string) The id for the order.
174 * 'created_at' => (string) The date and time the order was created.
175 * 'updated_at' => (string) The date and time the order was last updated.
176 * ]
177 * @param int $id Required. The id of the order to create or update.
178 * @param array $params Required. Additional parameters for order item creation|update.
179 * $params => (array) Required. Array of order item details.
180 * [
181 * 'id' => (int) The id for the order item|null if not.
182 * 'order_id' => (int) The ID of the order to which the item belongs.
183 * 'post_id' => (int) The product ID associated with the order item.
184 * 'object_id' => (int) The variation ID of the order item.
185 * 'thumbnail' => (string) The URL of the thumbnail of order item.
186 * 'unit_price' => (float) The price of the item.
187 * 'title' => (string) The name of the item.
188 * 'quantity' => (int) The quantity of the item.
189 * 'fulfillment_type' => (string) Type (e.g., 'physical', 'digital').
190 * 'stockStatus' => (string) (e.g., 'in-stock'|'out-of-stock').
191 * 'stock' => (int) The current stock quantity.
192 * 'tax_amount' => (float) The tax amount for the item.
193 * 'discount_total' => (float) The total discount amount for the item.
194 * 'total' => (float) The total amount for the item.
195 * 'line_total' => (float) The total amount for the line
196 * ]
197 *
198 */
199 public static function updateOrInsertOrderItems($order, $id, $params = [], $couponCalculation = [])
200 {
201 if (empty($params) || !is_array($params)) {
202 return static::makeErrorResponse([
203 ['code' => 403, 'message' => __('No items given.', 'fluent-cart')]
204 ]);
205 }
206
207 $newItems = [];
208 $existingItems = [];
209
210 $variationIds = (new Collection($params))->pluck('object_id')->toArray();
211
212 $orderItems = static::getQuery()
213 ->where('order_id', $id)
214 ->whereIn('object_id', $variationIds)
215 ->get();
216
217 foreach ($params as $idx => &$item) {
218 $item['order_id'] = $id;
219 $productId = Arr::get($item, 'post_id');
220 $variationId = Arr::get($item, 'object_id', null);
221 $isCustom = Arr::get($item, 'other_info.is_custom', false);
222
223 if (isset($productId) && isset($variationId) && !$isCustom) {
224
225 $orderItem = $orderItems->where('post_id', $productId)
226 ->where('object_id', $variationId)->first();
227
228 $isExist = !empty($orderItem);
229
230 $itemData = Arr::only($item, ['id', 'title', 'post_id', 'object_id', 'post_title', 'quantity', 'unit_price', 'cost', 'tax_amount', 'discount_total', 'line_total']);
231 $itemData['subtotal'] = Arr::get($item, 'quantity', 0) * Arr::get($item, 'unit_price', 0);
232 $itemData['line_total'] = $itemData['subtotal'] - Arr::get($item, 'discount_total', 0);
233 $fulfillment_type = Arr::get($item, 'fulfillment_type', 'physical');
234
235
236 if (empty($isExist)) {
237 unset($itemData['id']);
238
239 // Snapshot the variant's attribute map + variation type into
240 // other_info so items added on order-edit carry the same data as
241 // the create path (AdminOrderProcessor), not just what the picker sent.
242 $otherInfo = Arr::get($item, 'other_info', []);
243 if (!is_array($otherInfo)) {
244 $otherInfo = [];
245 }
246 if (!array_key_exists('item_attributes', $otherInfo)) {
247 $otherInfo['item_attributes'] = AttributeHelper::getProductItemAttributes($variationId, $productId);
248 }
249 if (empty($otherInfo['variation_type'])) {
250 // Resolve server-side from the variation (same as the create
251 // path) — admin orders don't go through the cart, so the snapshot
252 // is the server's responsibility, not the request's.
253 $variation = ProductVariation::query()->with('product_detail')->find($variationId);
254 $otherInfo['variation_type'] = ($variation && $variation->product_detail) ? (string) $variation->product_detail->variation_type : '';
255 }
256
257 $item = wp_parse_args([
258 'order_id' => $id,
259 'cart_index' => $idx + 1,
260 'fulfillment_type' => $fulfillment_type,
261 'other_info' => json_encode($otherInfo),
262 'payment_type' => Arr::get($item, 'payment_type', Arr::get($item, 'other_info.payment_type', '')),
263 'shipping_charge' => Arr::get($item, 'shipping_charge', 0),
264 'created_at' => DateTime::now(),
265 'updated_at' => DateTime::now(),
266 'fulfilled_quantity' => $fulfillment_type === 'physical' ? 0 : Arr::get($item, 'quantity', 0)
267 ], $itemData);
268 $newItems[] = $item;
269 } else {
270 $existingData = Arr::only($itemData, ['id', 'quantity', 'unit_price', 'cost', 'subtotal', 'tax_amount', 'discount_total', 'line_total', 'shipping_charge']) + ['updated_at' => DateTime::now()];
271 $existingData['fulfilled_quantity'] = $fulfillment_type === 'physical' ? Arr::get($item, 'fulfilled_quantity', 0) : Arr::get($item, 'quantity', 0);
272 $incomingLineMeta = Arr::get($item, 'line_meta');
273 if (is_array($incomingLineMeta) && array_key_exists('coupon_discount', $incomingLineMeta)) {
274 $incomingLineMeta['coupon_discount'] = (int) $incomingLineMeta['coupon_discount'];
275 $existingData['line_meta'] = json_encode($incomingLineMeta);
276 }
277 $existingItems[] = $existingData;
278 }
279 }
280 else if(isset($productId) && isset($variationId) && $isCustom){
281 $oldItem = $orderItems->firstWhere('object_id', $variationId);
282 $filteredItem = (array) apply_filters('fluent_cart/order/custom_item_changed',
283 $oldItem,
284 $item
285 );
286
287 $filteredData = Arr::only($filteredItem, ['id', 'quantity', 'unit_price', 'cost', 'subtotal', 'tax_amount', 'discount_total', 'line_total', 'shipping_charge']
288 );
289
290 $filteredData['fulfilled_quantity'] = $fulfillment_type === 'physical'
291 ? Arr::get($item, 'fulfilled_quantity', 0)
292 : Arr::get($item, 'quantity', 0);
293
294 $existingItems[] = $filteredData;
295 }
296 }
297
298 // if any item is adjustment, then only add the adjustment item
299 $adjustmentItem = array_filter($newItems, function ($item) {
300 return Arr::get($item, 'payment_type') === 'adjustment';
301 });
302
303 if (count($adjustmentItem) > 0) {
304 $newItems = $adjustmentItem[0];
305 }
306
307 if (count($newItems) > 0) {
308 OrderItemResource::create($newItems, $order);
309 }
310
311 if (count($existingItems) > 0) {
312 OrderItemResource::update($existingItems, $order);
313 }
314
315 return static::makeSuccessResponse(
316 '',
317 __('Order items updated.', 'fluent-cart')
318 );
319 }
320
321 /**
322 * Retrieve the top-selling products based on the total quantity sold.
323 *
324 * @param array $params Optional. Additional parameters for retrieving top-selling products.
325 * [
326 * 'created_at' => (array) Optional. Filter results by creation date.
327 * [ "created_at" => [
328 * "column" => "created_at",
329 * "operator" => "between",
330 * "value" => "Date range e.g. start_date,end_date ]
331 * ],
332 * 'operator' => (string) Optional. Operator for the 'total_sold' condition.
333 * (e.g., '>', '=', '<', etc.)
334 * 'total_sold' => (int) Optional. Total quantity sold condition.
335 * ]
336 *
337 */
338 public static function topProductsSold($params = [])
339 {
340 $params = is_array($params) ? $params : [];
341
342 return OrderItem::search(Arr::only($params, ['created_at']))
343 ->select('post_id')
344 ->selectRaw('SUM(quantity) as total_sold')
345 ->groupBy('post_id')
346 ->orderBy(sanitize_sql_orderby('total_sold'), sanitize_sql_orderby('DESC'))
347 ->having('total_sold', Arr::get($params, 'operator'), Arr::get($params, 'total_sold'))
348 // ->with([
349 // 'product' => function(Builder $query){
350 // return $query->select('ID','post_title');
351 // }
352 // ])
353 ->withWhereHas('product', function ($query) {
354 $query->select('ID', 'post_title');
355 })
356 ->lazy()->forPage(1, 5);
357 }
358
359 public static function bulkDeleteByOrderIds($ids, $params = [])
360 {
361 return static::getQuery()->whereIn('order_id', $ids)->delete();
362 }
363
364 }
365