server-core-module 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/order.controller.d.ts +8 -0
- package/dist/controllers/order.controller.js +97 -0
- package/dist/controllers/product.controller.d.ts +8 -0
- package/dist/controllers/product.controller.js +83 -0
- package/dist/error.d.ts +17 -0
- package/dist/error.js +37 -0
- package/dist/models/order.model.d.ts +26 -0
- package/dist/models/order.model.js +52 -0
- package/dist/models/product.model.d.ts +16 -0
- package/dist/models/product.model.js +31 -0
- package/dist/repositories/order.repository.d.ts +26 -0
- package/dist/repositories/order.repository.js +107 -0
- package/dist/repositories/product.repository.d.ts +26 -0
- package/dist/repositories/product.repository.js +107 -0
- package/dist/utils/email.service.d.ts +4 -0
- package/dist/utils/email.service.js +161 -0
- package/dist/utils/paginate.util.d.ts +13 -0
- package/dist/utils/paginate.util.js +15 -0
- package/package.json +10 -3
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
export declare function useOrderController(): {
|
|
3
|
+
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
4
|
+
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
5
|
+
getById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
6
|
+
updateById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
7
|
+
deleteById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useOrderController = useOrderController;
|
|
7
|
+
const order_model_1 = require("../models/order.model");
|
|
8
|
+
const order_repository_1 = require("../repositories/order.repository");
|
|
9
|
+
const error_1 = require("../error");
|
|
10
|
+
const email_service_1 = require("../utils/email.service");
|
|
11
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
12
|
+
dotenv_1.default.config();
|
|
13
|
+
function useOrderController() {
|
|
14
|
+
const { getAll: _getAll, add: _add, getById: _getById, deleteById: _deleteById, updateById: _updateById } = (0, order_repository_1.useOrderRepository)();
|
|
15
|
+
async function add(req, res, next) {
|
|
16
|
+
const value = req.body;
|
|
17
|
+
const { error } = order_model_1.schemaOrder.validate(value);
|
|
18
|
+
if (error) {
|
|
19
|
+
next(new error_1.BadRequestError(error.details[0].message));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const message = await _add(value);
|
|
24
|
+
// ← dagdag mo dito
|
|
25
|
+
await (0, email_service_1.sendOrderConfirmation)(value.email, value.name, value.items, value.totalAmount, value.deliveryFee);
|
|
26
|
+
await (0, email_service_1.sendAdminNotification)(value.name, value.items, value.totalAmount, value.email, value.deliveryFee);
|
|
27
|
+
res.json({ message });
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
next(error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function getAll(req, res, next) {
|
|
34
|
+
try {
|
|
35
|
+
const status = req.query.status;
|
|
36
|
+
const page = Number(req.query.page) || 1;
|
|
37
|
+
const limit = Number(req.query.limit) || 10;
|
|
38
|
+
const items = await _getAll({ status, page, limit });
|
|
39
|
+
res.json(items);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
next(error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function getById(req, res, next) {
|
|
46
|
+
const id = req.params.id;
|
|
47
|
+
try {
|
|
48
|
+
const item = await _getById(id);
|
|
49
|
+
res.json(item);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
next(error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function updateById(req, res, next) {
|
|
56
|
+
try {
|
|
57
|
+
const id = req.params.id;
|
|
58
|
+
const value = req.body;
|
|
59
|
+
const { error } = order_model_1.schemaOrderUpdate.validate(value);
|
|
60
|
+
if (error) {
|
|
61
|
+
next(new error_1.BadRequestError(error.message));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await _updateById(id, value);
|
|
65
|
+
// fetch yung order para makuha email at name
|
|
66
|
+
const order = await _getById(id);
|
|
67
|
+
if (!order) {
|
|
68
|
+
res.status(404).json({ message: "Order not found" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (value.status) {
|
|
72
|
+
await (0, email_service_1.sendOrderStatusUpdate)(order.email, order.name, value.status);
|
|
73
|
+
}
|
|
74
|
+
res.json({ message: "Order updated successfully", order });
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
next(error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function deleteById(req, res, next) {
|
|
81
|
+
try {
|
|
82
|
+
const id = req.params.id;
|
|
83
|
+
await _deleteById(id);
|
|
84
|
+
res.json({ message: "Order deleted successfully" });
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
next(error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
add,
|
|
92
|
+
getAll,
|
|
93
|
+
getById,
|
|
94
|
+
updateById,
|
|
95
|
+
deleteById,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
export declare function useProductController(): {
|
|
3
|
+
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
4
|
+
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
5
|
+
getById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
6
|
+
updateById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
7
|
+
deleteById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useProductController = useProductController;
|
|
4
|
+
const product_model_1 = require("../models/product.model");
|
|
5
|
+
const product_repository_1 = require("../repositories/product.repository");
|
|
6
|
+
const error_1 = require("../error");
|
|
7
|
+
function useProductController() {
|
|
8
|
+
const { getAll: _getAll, add: _add, getById: _getById, deleteById: _deleteById, updateById: _updateById } = (0, product_repository_1.useProductRepository)();
|
|
9
|
+
async function add(req, res, next) {
|
|
10
|
+
const value = req.body;
|
|
11
|
+
const { error } = product_model_1.schemaProduct.validate(value);
|
|
12
|
+
if (error) {
|
|
13
|
+
next(new error_1.BadRequestError(error.details[0].message));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const message = await _add(value);
|
|
18
|
+
res.json({ message });
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
next(error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function getAll(req, res, next) {
|
|
25
|
+
try {
|
|
26
|
+
const category = req.query.category;
|
|
27
|
+
const page = Number(req.query.page) || 1;
|
|
28
|
+
const limit = Number(req.query.limit) || 10;
|
|
29
|
+
const items = await _getAll({ category, page, limit });
|
|
30
|
+
res.json(items);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
next(error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function getById(req, res, next) {
|
|
37
|
+
const id = req.params.id;
|
|
38
|
+
try {
|
|
39
|
+
const item = await _getById(id);
|
|
40
|
+
res.json(item);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
next(error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function updateById(req, res, next) {
|
|
47
|
+
try {
|
|
48
|
+
const id = req.params.id;
|
|
49
|
+
const value = req.body;
|
|
50
|
+
const { error } = product_model_1.schemaProductUpdate.validate(value);
|
|
51
|
+
if (error) {
|
|
52
|
+
next(new error_1.BadRequestError(error.message));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const updated = await _updateById(id, value);
|
|
56
|
+
if (!updated) {
|
|
57
|
+
res.status(404).json({ message: "Product not found" });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
res.json({ message: "Product updated successfully", updated });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
next(error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function deleteById(req, res, next) {
|
|
67
|
+
try {
|
|
68
|
+
const id = req.params.id;
|
|
69
|
+
await _deleteById(id);
|
|
70
|
+
res.json({ message: "Product deleted successfully" });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
next(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
add,
|
|
78
|
+
getAll,
|
|
79
|
+
getById,
|
|
80
|
+
updateById,
|
|
81
|
+
deleteById,
|
|
82
|
+
};
|
|
83
|
+
}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class AppError extends Error {
|
|
2
|
+
readonly statusCode: number;
|
|
3
|
+
readonly isOperational: boolean;
|
|
4
|
+
constructor(message: string, statusCode: number, isOperational?: boolean);
|
|
5
|
+
}
|
|
6
|
+
export declare class BadRequestError extends AppError {
|
|
7
|
+
constructor(message?: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class Unauthorized extends AppError {
|
|
10
|
+
constructor(message?: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class NotFoundError extends AppError {
|
|
13
|
+
constructor(message?: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class InternalServerError extends AppError {
|
|
16
|
+
constructor(message?: string);
|
|
17
|
+
}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InternalServerError = exports.NotFoundError = exports.Unauthorized = exports.BadRequestError = exports.AppError = void 0;
|
|
4
|
+
class AppError extends Error {
|
|
5
|
+
constructor(message, statusCode, isOperational = true) {
|
|
6
|
+
super(message);
|
|
7
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.isOperational = isOperational;
|
|
10
|
+
Error.captureStackTrace(this);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.AppError = AppError;
|
|
14
|
+
class BadRequestError extends AppError {
|
|
15
|
+
constructor(message = 'Bad Request') {
|
|
16
|
+
super(message, 400);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.BadRequestError = BadRequestError;
|
|
20
|
+
class Unauthorized extends AppError {
|
|
21
|
+
constructor(message = 'Unauthorized') {
|
|
22
|
+
super(message, 401);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.Unauthorized = Unauthorized;
|
|
26
|
+
class NotFoundError extends AppError {
|
|
27
|
+
constructor(message = 'Not Found') {
|
|
28
|
+
super(message, 404);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.NotFoundError = NotFoundError;
|
|
32
|
+
class InternalServerError extends AppError {
|
|
33
|
+
constructor(message = 'Internal Server Error') {
|
|
34
|
+
super(message, 500);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.InternalServerError = InternalServerError;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Joi from 'joi';
|
|
2
|
+
import { ObjectId } from 'mongodb';
|
|
3
|
+
export type TOrder = {
|
|
4
|
+
_id?: ObjectId;
|
|
5
|
+
name: string;
|
|
6
|
+
email: string;
|
|
7
|
+
phone: string;
|
|
8
|
+
address: string;
|
|
9
|
+
items: {
|
|
10
|
+
productId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
price: number;
|
|
13
|
+
quantity: number;
|
|
14
|
+
}[];
|
|
15
|
+
totalAmount: number;
|
|
16
|
+
note?: string;
|
|
17
|
+
deliveryDate?: Date;
|
|
18
|
+
status?: string;
|
|
19
|
+
createdAt?: Date;
|
|
20
|
+
updatedAt?: Date;
|
|
21
|
+
location?: string;
|
|
22
|
+
deliveryFee?: number;
|
|
23
|
+
};
|
|
24
|
+
export declare const schemaOrder: Joi.ObjectSchema<any>;
|
|
25
|
+
export declare const schemaOrderUpdate: Joi.ObjectSchema<any>;
|
|
26
|
+
export declare function modelOrder(value: TOrder): TOrder;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.schemaOrderUpdate = exports.schemaOrder = void 0;
|
|
7
|
+
exports.modelOrder = modelOrder;
|
|
8
|
+
const joi_1 = __importDefault(require("joi"));
|
|
9
|
+
exports.schemaOrder = joi_1.default.object({
|
|
10
|
+
name: joi_1.default.string().required(),
|
|
11
|
+
email: joi_1.default.string().email().required(),
|
|
12
|
+
phone: joi_1.default.string().required(),
|
|
13
|
+
address: joi_1.default.string().required(),
|
|
14
|
+
items: joi_1.default.array().items(joi_1.default.object({
|
|
15
|
+
productId: joi_1.default.string().required(),
|
|
16
|
+
name: joi_1.default.string().required(),
|
|
17
|
+
price: joi_1.default.number().min(0).required(),
|
|
18
|
+
quantity: joi_1.default.number().min(1).required(),
|
|
19
|
+
})).required(),
|
|
20
|
+
totalAmount: joi_1.default.number().min(0).required(),
|
|
21
|
+
note: joi_1.default.string().optional(),
|
|
22
|
+
deliveryDate: joi_1.default.date().optional(),
|
|
23
|
+
status: joi_1.default.string().default("pending"),
|
|
24
|
+
location: joi_1.default.string().optional(),
|
|
25
|
+
deliveryFee: joi_1.default.number().min(0).optional(),
|
|
26
|
+
});
|
|
27
|
+
exports.schemaOrderUpdate = joi_1.default.object({
|
|
28
|
+
name: joi_1.default.string(),
|
|
29
|
+
email: joi_1.default.string().email(),
|
|
30
|
+
phone: joi_1.default.string(),
|
|
31
|
+
address: joi_1.default.string(),
|
|
32
|
+
items: joi_1.default.array().items(joi_1.default.object({
|
|
33
|
+
productId: joi_1.default.string().required(),
|
|
34
|
+
name: joi_1.default.string().required(),
|
|
35
|
+
price: joi_1.default.number().min(0).required(),
|
|
36
|
+
quantity: joi_1.default.number().min(1).required(),
|
|
37
|
+
})),
|
|
38
|
+
totalAmount: joi_1.default.number().min(0),
|
|
39
|
+
note: joi_1.default.string(),
|
|
40
|
+
deliveryDate: joi_1.default.date(),
|
|
41
|
+
status: joi_1.default.string(),
|
|
42
|
+
location: joi_1.default.string(),
|
|
43
|
+
deliveryFee: joi_1.default.number().min(0),
|
|
44
|
+
});
|
|
45
|
+
function modelOrder(value) {
|
|
46
|
+
return {
|
|
47
|
+
...value,
|
|
48
|
+
status: value.status || "pending",
|
|
49
|
+
createdAt: value.createdAt || new Date(),
|
|
50
|
+
updatedAt: new Date(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Joi from 'joi';
|
|
2
|
+
import { ObjectId } from 'mongodb';
|
|
3
|
+
export type TProduct = {
|
|
4
|
+
_id?: ObjectId;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
price: number;
|
|
8
|
+
imageUrl?: string;
|
|
9
|
+
status?: string;
|
|
10
|
+
createdAt?: Date;
|
|
11
|
+
updatedAt?: Date;
|
|
12
|
+
category?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const schemaProduct: Joi.ObjectSchema<any>;
|
|
15
|
+
export declare const schemaProductUpdate: Joi.ObjectSchema<any>;
|
|
16
|
+
export declare function modelProduct(value: TProduct): TProduct;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.schemaProductUpdate = exports.schemaProduct = void 0;
|
|
7
|
+
exports.modelProduct = modelProduct;
|
|
8
|
+
const joi_1 = __importDefault(require("joi"));
|
|
9
|
+
exports.schemaProduct = joi_1.default.object({
|
|
10
|
+
name: joi_1.default.string().required(),
|
|
11
|
+
description: joi_1.default.string().required(),
|
|
12
|
+
price: joi_1.default.number().min(0).required(),
|
|
13
|
+
imageUrl: joi_1.default.string().optional(),
|
|
14
|
+
status: joi_1.default.string().default("available"),
|
|
15
|
+
category: joi_1.default.string().optional(),
|
|
16
|
+
});
|
|
17
|
+
exports.schemaProductUpdate = joi_1.default.object({
|
|
18
|
+
name: joi_1.default.string(),
|
|
19
|
+
description: joi_1.default.string(),
|
|
20
|
+
price: joi_1.default.number().min(0),
|
|
21
|
+
imageUrl: joi_1.default.string(),
|
|
22
|
+
status: joi_1.default.string(),
|
|
23
|
+
category: joi_1.default.string(),
|
|
24
|
+
});
|
|
25
|
+
function modelProduct(value) {
|
|
26
|
+
return {
|
|
27
|
+
...value,
|
|
28
|
+
createdAt: value.createdAt || new Date(),
|
|
29
|
+
updatedAt: new Date(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ObjectId, Db } from "mongodb";
|
|
2
|
+
import { TOrder } from "../models/order.model";
|
|
3
|
+
export declare function setDb(database: Db): void;
|
|
4
|
+
export declare function useOrderRepository(): {
|
|
5
|
+
add: (value: TOrder) => Promise<ObjectId>;
|
|
6
|
+
getAll: ({ page, limit, status, }?: {
|
|
7
|
+
page?: number;
|
|
8
|
+
limit?: number;
|
|
9
|
+
status?: string;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
items: any[];
|
|
12
|
+
totalPages: number;
|
|
13
|
+
currentPage: number;
|
|
14
|
+
pages?: undefined;
|
|
15
|
+
pageRange?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
items: any[];
|
|
18
|
+
pages: number;
|
|
19
|
+
pageRange: string;
|
|
20
|
+
totalPages?: undefined;
|
|
21
|
+
currentPage?: undefined;
|
|
22
|
+
}>;
|
|
23
|
+
getById: (id: string) => Promise<import("mongodb").WithId<import("bson").Document>>;
|
|
24
|
+
updateById: (id: string, value: Partial<TOrder>) => Promise<number>;
|
|
25
|
+
deleteById: (id: string) => Promise<string>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setDb = setDb;
|
|
4
|
+
exports.useOrderRepository = useOrderRepository;
|
|
5
|
+
const mongodb_1 = require("mongodb");
|
|
6
|
+
const order_model_1 = require("../models/order.model");
|
|
7
|
+
const paginate_util_1 = require("../utils/paginate.util");
|
|
8
|
+
let db;
|
|
9
|
+
function setDb(database) {
|
|
10
|
+
db = database;
|
|
11
|
+
}
|
|
12
|
+
function useOrderRepository() {
|
|
13
|
+
const collection = db.collection('orders');
|
|
14
|
+
//CREATE INDEXES
|
|
15
|
+
async function createIndexes() {
|
|
16
|
+
try {
|
|
17
|
+
await collection.createIndexes([
|
|
18
|
+
{ key: { name: 1 } },
|
|
19
|
+
{ key: { createdAt: 1 } },
|
|
20
|
+
]);
|
|
21
|
+
return "Indexes created successfully";
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw new Error(`Error creating indexes: ${error.message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//ADD ORDER
|
|
28
|
+
async function add(value) {
|
|
29
|
+
try {
|
|
30
|
+
value = (0, order_model_1.modelOrder)(value);
|
|
31
|
+
const result = await collection.insertOne(value);
|
|
32
|
+
return result.insertedId;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new Error(`Error adding order: ${error.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//GET ALL ORDERS
|
|
39
|
+
async function getAll({ page = 1, limit = 10, status = "", } = {}) {
|
|
40
|
+
page = page > 0 ? page - 1 : 0;
|
|
41
|
+
const query = {};
|
|
42
|
+
if (status)
|
|
43
|
+
query.status = status;
|
|
44
|
+
try {
|
|
45
|
+
const items = await collection.aggregate([
|
|
46
|
+
{ $match: query },
|
|
47
|
+
{ $skip: page * limit },
|
|
48
|
+
{ $limit: limit },
|
|
49
|
+
]).toArray();
|
|
50
|
+
const length = await collection.countDocuments(query);
|
|
51
|
+
return (0, paginate_util_1.paginate)(items, page, limit, length);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error("Failed to get orders: " + error.message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//GET ORDER BY ID
|
|
58
|
+
async function getById(id) {
|
|
59
|
+
try {
|
|
60
|
+
const item = await collection.findOne({ _id: new mongodb_1.ObjectId(id) });
|
|
61
|
+
return item;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new Error("Failed to get order: " + error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//UPDATE BY ID
|
|
68
|
+
async function updateById(id, value) {
|
|
69
|
+
try {
|
|
70
|
+
new mongodb_1.ObjectId(id);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new Error("Invalid ID format");
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
value.updatedAt = new Date();
|
|
77
|
+
const result = await collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $set: value });
|
|
78
|
+
return result.modifiedCount;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw new Error("Failed to update order:" + error.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//DELETE BY ID
|
|
85
|
+
async function deleteById(id) {
|
|
86
|
+
try {
|
|
87
|
+
id = new mongodb_1.ObjectId(id);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new Error("Failed to delete order: " + error);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await collection.deleteOne({ _id: id });
|
|
94
|
+
return "Order deleted successfully";
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error("Failed to delete order: " + error.message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
add,
|
|
102
|
+
getAll,
|
|
103
|
+
getById,
|
|
104
|
+
updateById,
|
|
105
|
+
deleteById,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ObjectId, Db } from "mongodb";
|
|
2
|
+
import { TProduct } from "../models/product.model";
|
|
3
|
+
export declare function setDb(database: Db): void;
|
|
4
|
+
export declare function useProductRepository(): {
|
|
5
|
+
add: (value: TProduct) => Promise<ObjectId>;
|
|
6
|
+
getAll: ({ page, limit, category, }?: {
|
|
7
|
+
page?: number;
|
|
8
|
+
limit?: number;
|
|
9
|
+
category?: string;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
items: any[];
|
|
12
|
+
totalPages: number;
|
|
13
|
+
currentPage: number;
|
|
14
|
+
pages?: undefined;
|
|
15
|
+
pageRange?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
items: any[];
|
|
18
|
+
pages: number;
|
|
19
|
+
pageRange: string;
|
|
20
|
+
totalPages?: undefined;
|
|
21
|
+
currentPage?: undefined;
|
|
22
|
+
}>;
|
|
23
|
+
getById: (id: string) => Promise<import("mongodb").WithId<import("bson").Document>>;
|
|
24
|
+
updateById: (id: string, value: Partial<TProduct>) => Promise<number>;
|
|
25
|
+
deleteById: (id: string) => Promise<string>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setDb = setDb;
|
|
4
|
+
exports.useProductRepository = useProductRepository;
|
|
5
|
+
const mongodb_1 = require("mongodb");
|
|
6
|
+
const product_model_1 = require("../models/product.model");
|
|
7
|
+
const paginate_util_1 = require("../utils/paginate.util");
|
|
8
|
+
let db;
|
|
9
|
+
function setDb(database) {
|
|
10
|
+
db = database;
|
|
11
|
+
}
|
|
12
|
+
function useProductRepository() {
|
|
13
|
+
const collection = db.collection('products');
|
|
14
|
+
//CREATE INDEXES
|
|
15
|
+
async function createIndexes() {
|
|
16
|
+
try {
|
|
17
|
+
await collection.createIndexes([
|
|
18
|
+
{ key: { name: 1 } },
|
|
19
|
+
{ key: { createdAt: 1 } },
|
|
20
|
+
]);
|
|
21
|
+
return "Indexes created successfully";
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw new Error(`Error creating indexes: ${error.message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//ADD PRODUCT
|
|
28
|
+
async function add(value) {
|
|
29
|
+
try {
|
|
30
|
+
value = (0, product_model_1.modelProduct)(value);
|
|
31
|
+
const result = await collection.insertOne(value);
|
|
32
|
+
return result.insertedId;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new Error(`Error adding product: ${error.message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//GET ALL PRODUCTS
|
|
39
|
+
async function getAll({ page = 1, limit = 10, category = "", } = {}) {
|
|
40
|
+
page = page > 0 ? page - 1 : 0;
|
|
41
|
+
const query = {};
|
|
42
|
+
if (category)
|
|
43
|
+
query.category = category;
|
|
44
|
+
try {
|
|
45
|
+
const items = await collection.aggregate([
|
|
46
|
+
{ $match: query },
|
|
47
|
+
{ $skip: page * limit },
|
|
48
|
+
{ $limit: limit },
|
|
49
|
+
]).toArray();
|
|
50
|
+
const length = await collection.countDocuments(query);
|
|
51
|
+
return (0, paginate_util_1.paginate)(items, page, limit, length);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error("Failed to get products: " + error.message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//GET PRODUCT BY ID
|
|
58
|
+
async function getById(id) {
|
|
59
|
+
try {
|
|
60
|
+
const item = await collection.findOne({ _id: new mongodb_1.ObjectId(id) });
|
|
61
|
+
return item;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new Error("Failed to get product: " + error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//UPDATE BY ID
|
|
68
|
+
async function updateById(id, value) {
|
|
69
|
+
try {
|
|
70
|
+
new mongodb_1.ObjectId(id);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw new Error("Invalid ID format");
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
value.updatedAt = new Date();
|
|
77
|
+
const result = await collection.updateOne({ _id: new mongodb_1.ObjectId(id) }, { $set: value });
|
|
78
|
+
return result.modifiedCount;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw new Error("Failed to update item:" + error.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//DELETE BY ID
|
|
85
|
+
async function deleteById(id) {
|
|
86
|
+
try {
|
|
87
|
+
id = new mongodb_1.ObjectId(id);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new Error("Failed to delete product: " + error);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await collection.deleteOne({ _id: id });
|
|
94
|
+
return "Product deleted successfully";
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error("Failed to delete product: " + error.message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
add,
|
|
102
|
+
getAll,
|
|
103
|
+
getById,
|
|
104
|
+
updateById,
|
|
105
|
+
deleteById,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function sendOrderConfirmation(email: string, name: string, items: any[], totalAmount: number, deliveryFee?: number): Promise<void>;
|
|
2
|
+
export declare function sendOrderStatusUpdate(email: string, name: string, status: string): Promise<void>;
|
|
3
|
+
export declare function sendAdminNotification(name: string, items: any[], totalAmount: number, customerEmail: string, deliveryFee?: number): Promise<void>;
|
|
4
|
+
export declare function sendContactEmail(name: string, email: string, phone: string, eventType: string, message: string): Promise<void>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sendOrderConfirmation = sendOrderConfirmation;
|
|
7
|
+
exports.sendOrderStatusUpdate = sendOrderStatusUpdate;
|
|
8
|
+
exports.sendAdminNotification = sendAdminNotification;
|
|
9
|
+
exports.sendContactEmail = sendContactEmail;
|
|
10
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
11
|
+
function createTransporter() {
|
|
12
|
+
return nodemailer_1.default.createTransport({
|
|
13
|
+
service: "gmail",
|
|
14
|
+
auth: {
|
|
15
|
+
user: process.env.EMAIL_USER,
|
|
16
|
+
pass: process.env.EMAIL_PASS,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async function sendOrderConfirmation(email, name, items, totalAmount, deliveryFee) {
|
|
21
|
+
console.log("Sending email to:", email);
|
|
22
|
+
try {
|
|
23
|
+
const transporter = createTransporter();
|
|
24
|
+
const itemsList = items.map(item => `<tr>
|
|
25
|
+
<td>${item.name}</td>
|
|
26
|
+
<td>${item.quantity}</td>
|
|
27
|
+
<td>₱${item.price}</td>
|
|
28
|
+
<td>₱${item.price * item.quantity}</td>
|
|
29
|
+
</tr>`).join("");
|
|
30
|
+
await transporter.sendMail({
|
|
31
|
+
from: `"Cesar's Flower Shop 🌸" <${process.env.EMAIL_USER}>`,
|
|
32
|
+
to: email,
|
|
33
|
+
subject: "Order Received! 🌸",
|
|
34
|
+
html: `
|
|
35
|
+
<h2>Hi ${name}!</h2>
|
|
36
|
+
<p>Your order has been received! 🌸</p>
|
|
37
|
+
<table border="1" cellpadding="8" cellspacing="0" style="border-collapse: collapse;">
|
|
38
|
+
<tr>
|
|
39
|
+
<th>Item</th>
|
|
40
|
+
<th>Qty</th>
|
|
41
|
+
<th>Price</th>
|
|
42
|
+
<th>Subtotal</th>
|
|
43
|
+
</tr>
|
|
44
|
+
${itemsList}
|
|
45
|
+
</table>
|
|
46
|
+
<h3>Items Subtotal: ₱${totalAmount - (deliveryFee || 0)}</h3>
|
|
47
|
+
<h3>Delivery Fee: ₱${deliveryFee || 0}</h3>
|
|
48
|
+
<h3>Total: ₱${totalAmount}</h3>
|
|
49
|
+
<p>We will confirm your order soon.</p>
|
|
50
|
+
<p>Thank you for ordering from Cesar's Flower Shop!</p>
|
|
51
|
+
`,
|
|
52
|
+
});
|
|
53
|
+
console.log("Email sent successfully!");
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error("Email error:", error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function sendOrderStatusUpdate(email, name, status) {
|
|
60
|
+
try {
|
|
61
|
+
const transporter = createTransporter();
|
|
62
|
+
await transporter.sendMail({
|
|
63
|
+
from: `"Cesar's Flower Shop 🌸" <${process.env.EMAIL_USER}>`,
|
|
64
|
+
to: email,
|
|
65
|
+
subject: `Order ${status}! 🌸`,
|
|
66
|
+
html: `
|
|
67
|
+
<h2>Hi ${name}!</h2>
|
|
68
|
+
<p>Your order is now <strong>${status}</strong>! 🌸</p>
|
|
69
|
+
<br/>
|
|
70
|
+
<p>Thank you for ordering from Cesar's Flower Shop!</p>
|
|
71
|
+
`,
|
|
72
|
+
});
|
|
73
|
+
console.log("Status email sent!");
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error("Status email error:", error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function sendAdminNotification(name, items, totalAmount, customerEmail, deliveryFee) {
|
|
80
|
+
try {
|
|
81
|
+
const transporter = createTransporter();
|
|
82
|
+
const itemsList = items.map(item => `<tr>
|
|
83
|
+
<td>${item.name}</td>
|
|
84
|
+
<td>${item.quantity}</td>
|
|
85
|
+
<td>₱${item.price}</td>
|
|
86
|
+
<td>₱${item.price * item.quantity}</td>
|
|
87
|
+
</tr>`).join("");
|
|
88
|
+
await transporter.sendMail({
|
|
89
|
+
from: `"Cesar's Flower Shop 🌸" <${process.env.EMAIL_USER}>`,
|
|
90
|
+
to: process.env.EMAIL_USER,
|
|
91
|
+
subject: `New Order from ${name}! 🌸`,
|
|
92
|
+
html: `
|
|
93
|
+
<h2>New Order Received! 🌸</h2>
|
|
94
|
+
<p><strong>Customer:</strong> ${name}</p>
|
|
95
|
+
<p><strong>Email:</strong> ${customerEmail}</p>
|
|
96
|
+
<table border="1" cellpadding="8" cellspacing="0">
|
|
97
|
+
<tr>
|
|
98
|
+
<th>Item</th>
|
|
99
|
+
<th>Qty</th>
|
|
100
|
+
<th>Price</th>
|
|
101
|
+
<th>Subtotal</th>
|
|
102
|
+
</tr>
|
|
103
|
+
${itemsList}
|
|
104
|
+
<tr>
|
|
105
|
+
<td colspan="3"><strong>Items Subtotal</strong></td>
|
|
106
|
+
<td>₱${totalAmount - (deliveryFee || 0)}</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<tr>
|
|
109
|
+
<td colspan="3"><strong>Delivery Fee</strong></td>
|
|
110
|
+
<td>₱${deliveryFee || 0}</td>
|
|
111
|
+
</tr>
|
|
112
|
+
<tr>
|
|
113
|
+
<td colspan="3"><strong>Total</strong></td>
|
|
114
|
+
<td><strong>₱${totalAmount}</strong></td>
|
|
115
|
+
</tr>
|
|
116
|
+
</table>
|
|
117
|
+
<p>Login to admin panel to confirm the order!</p>
|
|
118
|
+
`,
|
|
119
|
+
});
|
|
120
|
+
console.log("Admin notified!");
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error("Admin email error:", error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function sendContactEmail(name, email, phone, eventType, message) {
|
|
127
|
+
try {
|
|
128
|
+
const transporter = createTransporter();
|
|
129
|
+
await transporter.sendMail({
|
|
130
|
+
from: `"Cesar's Flower Shop 🌸" <${process.env.EMAIL_USER}>`,
|
|
131
|
+
to: process.env.EMAIL_USER,
|
|
132
|
+
subject: `New Inquiry from ${name} - ${eventType} 🌸`,
|
|
133
|
+
html: `
|
|
134
|
+
<h2>New Customer Inquiry! 🌸</h2>
|
|
135
|
+
<p><strong>Name:</strong> ${name}</p>
|
|
136
|
+
<p><strong>Email:</strong> ${email}</p>
|
|
137
|
+
<p><strong>Phone:</strong> ${phone}</p>
|
|
138
|
+
<p><strong>Event Type:</strong> ${eventType}</p>
|
|
139
|
+
<p><strong>Message:</strong></p>
|
|
140
|
+
<p>${message}</p>
|
|
141
|
+
`,
|
|
142
|
+
});
|
|
143
|
+
await transporter.sendMail({
|
|
144
|
+
from: `"Cesar's Flower Shop 🌸" <${process.env.EMAIL_USER}>`,
|
|
145
|
+
to: email,
|
|
146
|
+
subject: `We received your message! 🌸`,
|
|
147
|
+
html: `
|
|
148
|
+
<h2>Hi ${name}! 🌸</h2>
|
|
149
|
+
<p>Thank you for reaching out to Cesar's Flower Shop!</p>
|
|
150
|
+
<p>We have received your inquiry about <strong>${eventType}</strong>.</p>
|
|
151
|
+
<p>We will get back to you as soon as possible.</p>
|
|
152
|
+
<br/>
|
|
153
|
+
<p>Thank you for choosing Cesar's Flower Shop! 🌺</p>
|
|
154
|
+
`,
|
|
155
|
+
});
|
|
156
|
+
console.log("Contact email sent!");
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error("Contact email error:", error);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function paginate(items: any[], page: number, limit: number, length: number): {
|
|
2
|
+
items: any[];
|
|
3
|
+
totalPages: number;
|
|
4
|
+
currentPage: number;
|
|
5
|
+
pages?: undefined;
|
|
6
|
+
pageRange?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
items: any[];
|
|
9
|
+
pages: number;
|
|
10
|
+
pageRange: string;
|
|
11
|
+
totalPages?: undefined;
|
|
12
|
+
currentPage?: undefined;
|
|
13
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.paginate = paginate;
|
|
4
|
+
function paginate(items, page, limit, length) {
|
|
5
|
+
if (length === 0) {
|
|
6
|
+
return { items: [], totalPages: 0, currentPage: 0 };
|
|
7
|
+
}
|
|
8
|
+
const startIndex = page * limit + 1;
|
|
9
|
+
const endIndex = Math.min(startIndex + limit - 1, length);
|
|
10
|
+
return {
|
|
11
|
+
items,
|
|
12
|
+
pages: Math.ceil(length / limit),
|
|
13
|
+
pageRange: `${startIndex}-${endIndex} of ${length}`,
|
|
14
|
+
};
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "server-core-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
7
|
+
"start": "ts-node src/server.ts",
|
|
8
|
+
"dev": "nodemon --exec ts-node src/server.ts",
|
|
9
|
+
"build": "tsc"
|
|
8
10
|
},
|
|
9
11
|
"keywords": [],
|
|
10
12
|
"author": "",
|
|
11
13
|
"license": "ISC",
|
|
12
14
|
"type": "commonjs",
|
|
13
15
|
"dependencies": {
|
|
16
|
+
"cloudinary": "^2.9.0",
|
|
17
|
+
"cors": "^2.8.6",
|
|
14
18
|
"dotenv": "^17.3.1",
|
|
15
19
|
"express": "^5.2.1",
|
|
16
20
|
"joi": "^18.0.2",
|
|
21
|
+
"jsonwebtoken": "^9.0.3",
|
|
17
22
|
"mongodb": "^7.1.0",
|
|
18
23
|
"nodemailer": "^8.0.1"
|
|
19
24
|
},
|
|
20
25
|
"devDependencies": {
|
|
21
26
|
"@types/express": "^5.0.6",
|
|
27
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
22
28
|
"@types/node": "^25.3.0",
|
|
23
29
|
"@types/nodemailer": "^7.0.11",
|
|
30
|
+
"nodemon": "^3.1.14",
|
|
24
31
|
"ts-node": "^10.9.2",
|
|
25
32
|
"typescript": "^5.9.3"
|
|
26
33
|
}
|
|
27
|
-
}
|
|
34
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"strict": false,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"declaration": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules"]
|
|
14
|
+
}
|