Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.

Commit 046a0c9

Browse files
committed
feat(orders): update stock based on order status change
1 parent c87e3e8 commit 046a0c9

5 files changed

Lines changed: 167 additions & 25 deletions

File tree

src/config/strings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ const Strings = {
180180
ORDER_ALREADY_EXISTS: "Order already exist! Please check your orders in the orders page.",
181181
ORDER_UPDATE_ERROR: "Something went wrong while updating order.",
182182
ORDER_UNAVAILABLE: "Product is unavailable!",
183+
ORDER_UPDATE_STATUS_NO_STOCK: "Order status cannot be updated, product is out of stock!",
183184
ORDER_EMPTY_PRODUCT_ID: "Product ID is empty!",
184185
ORDER_EMPTY_STUDENT_ID: "Student ID is empty!",
185186
ORDER_EMPTY_STUDENT_FIRST_NAME: "Student first name is empty!",

src/core/orders.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ export function putOrders(request: Request, response: Response) {
280280
return;
281281
}
282282

283+
if (error === ErrorTypes.DB_PRODUCT_NO_STOCK) {
284+
response.status(400).send(result.error(Strings.ORDER_UPDATE_STATUS_NO_STOCK));
285+
return;
286+
}
287+
283288
// If not success
284289
if (!dateStamp) {
285290
response.status(400).send(result.error(Strings.ORDER_UPDATE_ERROR));

src/db/models/order.ts

Lines changed: 135 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { generateReference, generateToken, sanitize } from "../../utils/security
66
import { OrderRequest, PaginationRequest } from "../../types/request";
77
import { PaginationQuery, paginationWrapper } from "../../utils/query";
88
import { OrderColumns, ProductColumns, Tables } from "../structure";
9+
import { mapOrderStatusLabel } from "../../utils/string";
910
import { sendEmail } from "../../utils/smtp";
1011
import { getFile } from "../../utils/file";
1112
import { Log } from "../../utils/log";
@@ -407,7 +408,7 @@ export class Order extends DatabaseModel {
407408
}
408409

409410
function decrementStock() {
410-
Order.decrementStock(order.products_id, order.variations_id || null, error => {
411+
Order.updateStock(false, order.products_id, order.variations_id || null, error => {
411412
if (error === ErrorTypes.DB_ERROR) {
412413
Log.e(`Student #${studentID || order.student_id}: Error decrementing stock`);
413414

@@ -489,33 +490,142 @@ export class Order extends DatabaseModel {
489490
const db = Database.getInstance();
490491
// Default data to set
491492
let data = `${sanitize(key)} = ?`
492-
493-
// If key is status_id
493+
494+
// Split id (B and N)
495+
const [ TYPE, ID ] = id.split("-");
496+
497+
// If updating status
494498
if (key === OrderColumns.STATUS) {
495499
data = `${OrderColumns.STATUS} = ?, ${OrderColumns.STATUS_UPDATED} = NOW()`;
496-
}
497500

498-
// Split id (B and N)
499-
const [ TYPE, ID ] = id.split("-");
501+
// Find order
502+
Order.find({
503+
search_column: `["${OrderColumns.ID}"]`,
504+
search_value: `["${ID}"]`,
505+
limit: "1"
506+
}, (error, orders) => {
507+
// Get order
508+
const order = orders && orders?.length > 0 ? orders[0] : null;
500509

501-
// Query the database
502-
db.query(`UPDATE ${TYPE === 'B' ? Tables.ORDERS : Tables.NON_BSCS_ORDERS } SET ${data}, ${OrderColumns.EDIT_DATE} = NOW() WHERE id = ?`, [value, ID], (error, results) => {
503-
// If has an error
504-
if (error) {
505-
Log.e(error.message);
506-
callback(ErrorTypes.DB_ERROR);
507-
return;
508-
}
510+
// If has an error
511+
if (error === ErrorTypes.DB_ERROR) {
512+
Log.e(`Student #${order?.student_id}: Error getting order while updating stock number`, true);
513+
update();
514+
return;
515+
}
509516

510-
// If no results
511-
if (results.affectedRows === 0) {
512-
callback(ErrorTypes.DB_EMPTY_RESULT);
513-
return;
514-
}
517+
// If no results
518+
if (error === ErrorTypes.DB_EMPTY_RESULT) {
519+
Log.e(`Student #${order?.student_id}: Error getting order while updating stock number because order #${id} not found!`, true);
520+
update();
521+
return;
522+
}
515523

516-
// Otherwise, return success
517-
callback(null, getDatestamp());
518-
});
524+
const isFromPendingOrComplete = order?.status == OrderStatus.PENDING_PAYMENT || order?.status == OrderStatus.COMPLETED;
525+
// If status is to cancelled, removed, rejected
526+
const toIncrement = [OrderStatus.CANCELLED_BY_ADMIN, OrderStatus.CANCELLED_BY_USER, OrderStatus.REJECTED, OrderStatus.REMOVED].includes(parseInt(value));
527+
528+
// Log message
529+
Log.i("Order #" + id + " is " + mapOrderStatusLabel(parseInt(value)).toLowerCase());
530+
531+
// INCREMENT
532+
if (isFromPendingOrComplete && toIncrement) {
533+
// Log message
534+
Log.i("Incrementing stock of order #" + id, true);
535+
// Increment stock
536+
Order.updateStock(true, order?.products_id || 0, order?.variations_id || null, error => {
537+
if (error === ErrorTypes.DB_ERROR) {
538+
Log.e(`Student #${order?.student_id}: Error incrementing stock`, true);
539+
}
540+
541+
// If no results
542+
if (error === ErrorTypes.DB_EMPTY_RESULT) {
543+
Log.e(`Student #${order?.student_id}: Error incrementing stock`, true);
544+
}
545+
546+
update();
547+
});
548+
549+
return;
550+
}
551+
552+
// DECREMENT
553+
if (!isFromPendingOrComplete && !toIncrement) {
554+
// Check if product has stock
555+
Product.fromId(order?.products_id || 0, (error, product) => {
556+
if (error === ErrorTypes.DB_ERROR) {
557+
Log.e(`Student #${order?.student_id}: Error getting product`, true);
558+
update();
559+
return;
560+
}
561+
562+
// If no results
563+
if (error === ErrorTypes.DB_EMPTY_RESULT) {
564+
Log.e(`Student #${order?.student_id}: Product not found while decrementing stock`, true);
565+
update();
566+
return;
567+
}
568+
569+
// If product has stock
570+
if (product && product.getStock() > 0) {
571+
// Log message
572+
Log.i("Decrementing stock of order #" + id, true);
573+
// Decrement stock
574+
Order.updateStock(false, order?.products_id || 0, order?.variations_id || null, error => {
575+
if (error === ErrorTypes.DB_ERROR) {
576+
Log.e(`Student #${order?.student_id}: Error decrementing stock`, true);
577+
}
578+
579+
// If no results
580+
if (error === ErrorTypes.DB_EMPTY_RESULT) {
581+
Log.e(`Student #${order?.student_id}: Error decrementing stock`, true);
582+
}
583+
584+
update();
585+
});
586+
587+
return;
588+
}
589+
590+
// Log message
591+
Log.w(`Student #${order?.student_id}: Product has no stock while decrementing stock`, true);
592+
// Callback error
593+
callback(ErrorTypes.DB_PRODUCT_NO_STOCK);
594+
});
595+
596+
return;
597+
}
598+
599+
// Otherwise, just return success
600+
update();
601+
});
602+
603+
return;
604+
}
605+
606+
function update() {
607+
// Query the database
608+
db.query(`UPDATE ${TYPE === 'B' ? Tables.ORDERS : Tables.NON_BSCS_ORDERS } SET ${data}, ${OrderColumns.EDIT_DATE} = NOW() WHERE id = ?`, [value, ID], (error, results) => {
609+
// If has an error
610+
if (error) {
611+
Log.e(error.message);
612+
callback(ErrorTypes.DB_ERROR);
613+
return;
614+
}
615+
616+
// If no results
617+
if (results.affectedRows === 0) {
618+
callback(ErrorTypes.DB_EMPTY_RESULT);
619+
return;
620+
}
621+
622+
// Otherwise, return success
623+
callback(null, getDatestamp());
624+
});
625+
}
626+
627+
// Otherwise, call update
628+
update();
519629
}
520630

521631
/**
@@ -648,14 +758,14 @@ export class Order extends DatabaseModel {
648758
}
649759

650760
/**
651-
* Decrement stock number
761+
* Update stock number
652762
*/
653-
private static decrementStock(products_id: number, variations_id: number | null, callback: (error: ErrorTypes | null) => void) {
763+
private static updateStock(isIncrement: boolean, products_id: number, variations_id: number | null, callback: (error: ErrorTypes | null) => void) {
654764
// Get database instance
655765
const db = Database.getInstance();
656766

657767
// Query the database
658-
db.query(`UPDATE ${variations_id === null ? 'products' : 'product_variations'} SET stock = stock - 1 WHERE ${variations_id === null ? 'id' : 'products_id'} = ? ${variations_id === null ? '' : 'AND variations_id = ?'}`, [products_id, variations_id], (error, results) => {
768+
db.query(`UPDATE ${variations_id === null ? 'products' : 'product_variations'} SET stock = stock ${isIncrement ? '+' : '-'} 1 WHERE ${variations_id === null ? 'id' : 'products_id'} = ? ${variations_id === null ? '' : 'AND variations_id = ?'}`, [products_id, variations_id], (error, results) => {
659769
// If has an error
660770
if (error) {
661771
Log.e(error.message);

src/types/enums.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export enum ErrorTypes {
1111
DB_STUDENT_ALREADY_EXISTS,
1212
DB_EMAIL_ALREADY_EXISTS,
1313
DB_PRODUCT_ALREADY_EXISTS,
14+
DB_PRODUCT_NO_STOCK,
1415
DB_EVENT_ALREADY_EXISTS,
1516
DB_ORDER_ALREADY_EXISTS,
1617
DB_UPDATE_EMPTY,

src/utils/string.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { OrderStatus } from "../types/enums";
2+
13
// Months with 31 days
24
const months31 = [1, 3, 5, 7, 8, 10, 12];
35
// Months with 30 days
@@ -94,4 +96,27 @@ export function parseText(text: string): object | null {
9496
} catch (error) {
9597
return null;
9698
}
99+
}
100+
101+
/*
102+
* Convert order status to label
103+
* @param status Generic status
104+
*/
105+
export function mapOrderStatusLabel(status: OrderStatus): string {
106+
switch (status) {
107+
case OrderStatus.PENDING_PAYMENT:
108+
return "Pending Payment";
109+
case OrderStatus.COMPLETED:
110+
return "Completed";
111+
case OrderStatus.CANCELLED_BY_USER:
112+
return "Cancelled by user";
113+
case OrderStatus.CANCELLED_BY_ADMIN:
114+
return "Cancelled by admin";
115+
case OrderStatus.REMOVED:
116+
return "Removed";
117+
case OrderStatus.REJECTED:
118+
return "Rejected";
119+
default:
120+
return "Unknown";
121+
}
97122
}

0 commit comments

Comments
 (0)