@b2y/ecommerce-common 1.0.0

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.
Files changed (68) hide show
  1. package/README.md +4 -0
  2. package/constants/AppConstants.js +4 -0
  3. package/constants/ReportConstants.js +15 -0
  4. package/constants/StatusMessageConstants.js +21 -0
  5. package/dbconnection/Connect.js +417 -0
  6. package/enum/AddressTypeEnum.js +7 -0
  7. package/enum/BooleanEnum.js +5 -0
  8. package/enum/EntityTypeEnum.js +10 -0
  9. package/enum/GenderEnum.js +7 -0
  10. package/enum/NotificationStatusEnum.js +6 -0
  11. package/enum/NotificationTypeEnum.js +10 -0
  12. package/enum/OrderStatusEnum.js +8 -0
  13. package/enum/PaymentMethodEnum.js +7 -0
  14. package/enum/PaymentStatusEnum.js +7 -0
  15. package/enum/PaymentTypeEnum.js +7 -0
  16. package/enum/PlatformEnum.js +5 -0
  17. package/enum/RegistrationStatusEnum.js +6 -0
  18. package/enum/SortByEnum.js +8 -0
  19. package/index.js +22 -0
  20. package/model/Address.js +114 -0
  21. package/model/AttributeType.js +51 -0
  22. package/model/AttributeValue.js +65 -0
  23. package/model/Banner.js +79 -0
  24. package/model/Brand.js +76 -0
  25. package/model/Cart.js +77 -0
  26. package/model/Category.js +73 -0
  27. package/model/CategoryAttributeType.js +63 -0
  28. package/model/City.js +49 -0
  29. package/model/Colour.js +53 -0
  30. package/model/Country.js +47 -0
  31. package/model/Customer.js +95 -0
  32. package/model/DeviceToken.js +52 -0
  33. package/model/Document.js +71 -0
  34. package/model/DynamicUIComponent.js +53 -0
  35. package/model/Feedback.js +80 -0
  36. package/model/Inventory.js +84 -0
  37. package/model/NotificationHistory.js +68 -0
  38. package/model/Order.js +95 -0
  39. package/model/OrderItem.js +99 -0
  40. package/model/OrderItemHistory.js +70 -0
  41. package/model/OrderStatus.js +49 -0
  42. package/model/Payment.js +101 -0
  43. package/model/PaymentMethod.js +37 -0
  44. package/model/PaymentStatus.js +37 -0
  45. package/model/PaymentType.js +37 -0
  46. package/model/Permission.js +55 -0
  47. package/model/Product.js +83 -0
  48. package/model/ProductGroup.js +48 -0
  49. package/model/ProductSpecification.js +66 -0
  50. package/model/ProductVariant.js +76 -0
  51. package/model/ProductVariantAttribute.js +59 -0
  52. package/model/Role.js +61 -0
  53. package/model/RolePermissionMapping.js +63 -0
  54. package/model/SpecificationType.js +42 -0
  55. package/model/State.js +56 -0
  56. package/model/Store.js +117 -0
  57. package/model/StoreUserMapping.js +44 -0
  58. package/model/Tenant.js +91 -0
  59. package/model/User.js +150 -0
  60. package/model/WishList.js +63 -0
  61. package/package.json +27 -0
  62. package/utility/AppUtil.js +58 -0
  63. package/utility/DateUtil.js +55 -0
  64. package/utility/ExcelUtil.js +125 -0
  65. package/utility/OrderTimeFilterUtil.js +86 -0
  66. package/utility/QueryUtil.js +262 -0
  67. package/utility/Razorpay.js +67 -0
  68. package/utility/VariantPriceUtil.js +55 -0
package/model/User.js ADDED
@@ -0,0 +1,150 @@
1
+ const { DataTypes } = require('sequelize');
2
+ const GenderEnum = require('../enum/GenderEnum')
3
+ module.exports = (sequelize) => {
4
+ return sequelize.define('User', {
5
+ UserID: {
6
+ type: DataTypes.UUID,
7
+ primaryKey: true,
8
+ allowNull: false,
9
+ defaultValue: DataTypes.UUIDV4
10
+ },
11
+ TenantID: {
12
+ type: DataTypes.UUID,
13
+ allowNull: false,
14
+ references: {
15
+ model: 'Tenant',
16
+ key: 'TenantID'
17
+ },
18
+ onDelete: 'CASCADE',
19
+ onUpdate: 'CASCADE'
20
+ },
21
+ FirstName: {
22
+ type: DataTypes.STRING(255),
23
+ allowNull: false
24
+ },
25
+ LastName: {
26
+ type: DataTypes.STRING(255),
27
+ allowNull: false
28
+ },
29
+ EmployeeID: {
30
+ type: DataTypes.STRING(50),
31
+ allowNull: false,
32
+ unique: true
33
+ },
34
+ Email: {
35
+ type: DataTypes.STRING(100),
36
+ allowNull: false,
37
+ },
38
+ Password: {
39
+ type: DataTypes.STRING(255),
40
+ allowNull: false
41
+ },
42
+ CountryCode: {
43
+ type: DataTypes.STRING(5),
44
+ allowNull: false
45
+ },
46
+ PhoneNumber: {
47
+ type: DataTypes.STRING(20),
48
+ allowNull: false,
49
+ },
50
+ Gender: {
51
+ type: DataTypes.ENUM(...Object.values(GenderEnum)),
52
+ allowNull: true
53
+ },
54
+ RoleID: {
55
+ type: DataTypes.UUID,
56
+ allowNull: false,
57
+ references: {
58
+ model: 'Role',
59
+ key: 'RoleID'
60
+ },
61
+ onDelete: 'RESTRICT',
62
+ onUpdate: 'CASCADE'
63
+ },
64
+ AddressLine: {
65
+ type: DataTypes.STRING(500),
66
+ allowNull: false
67
+ },
68
+ CityID: {
69
+ type: DataTypes.INTEGER,
70
+ allowNull: false,
71
+ references: {
72
+ model: 'City',
73
+ key: 'CityID'
74
+ },
75
+ onDelete: 'RESTRICT',
76
+ onUpdate: 'CASCADE'
77
+ },
78
+ StateID: {
79
+ type: DataTypes.INTEGER,
80
+ allowNull: false,
81
+ references: {
82
+ model: 'State',
83
+ key: 'StateID'
84
+ },
85
+ onDelete: 'RESTRICT',
86
+ onUpdate: 'CASCADE'
87
+ },
88
+ CountryID: {
89
+ type: DataTypes.INTEGER,
90
+ allowNull: false,
91
+ references: {
92
+ model: 'Country',
93
+ key: 'CountryID'
94
+ },
95
+ onDelete: 'RESTRICT',
96
+ onUpdate: 'CASCADE'
97
+ },
98
+ Zipcode: {
99
+ type: DataTypes.STRING(10),
100
+ allowNull: false
101
+ },
102
+ OTP: {
103
+ type: DataTypes.STRING(10),
104
+ allowNull: true
105
+ },
106
+ OtpExpiry: {
107
+ type: DataTypes.DATE,
108
+ allowNull: true
109
+ },
110
+ IsActive: {
111
+ type: DataTypes.BOOLEAN,
112
+ defaultValue: true
113
+ },
114
+ CreatedBy: {
115
+ type: DataTypes.UUID,
116
+ allowNull: false
117
+ },
118
+ CreatedAt: {
119
+ type: DataTypes.DATE,
120
+ defaultValue: DataTypes.NOW,
121
+ allowNull: false
122
+ },
123
+ UpdatedBy: {
124
+ type: DataTypes.UUID,
125
+ allowNull: false
126
+ },
127
+ UpdatedAt: {
128
+ type: DataTypes.DATE,
129
+ defaultValue: DataTypes.NOW,
130
+ allowNull: false
131
+ }
132
+ }, {
133
+ tableName: 'User',
134
+ timestamps: false,
135
+ indexes: [
136
+ {
137
+ name: "UQ_User_Tenant_Email",
138
+ unique: true,
139
+ fields: ["TenantID", "Email"],
140
+ },
141
+ {
142
+ name: "UQ_User_Tenant_Phone",
143
+ unique: true,
144
+ fields: ["TenantID", "CountryCode", "PhoneNumber"],
145
+ },
146
+ ],
147
+ });
148
+ };
149
+
150
+
@@ -0,0 +1,63 @@
1
+ const { DataTypes } = require('sequelize');
2
+
3
+ module.exports = (sequelize) => {
4
+ return sequelize.define('WishList', {
5
+ WishListID: {
6
+ type: DataTypes.UUID,
7
+ primaryKey: true,
8
+ allowNull: false,
9
+ defaultValue: DataTypes.UUIDV4
10
+ },
11
+ TenantID: {
12
+ type: DataTypes.UUID,
13
+ allowNull: false,
14
+ references: {
15
+ model: 'Tenant',
16
+ key: 'TenantID'
17
+ },
18
+ onDelete: 'CASCADE',
19
+ onUpdate: 'CASCADE'
20
+ },
21
+ ProductVariantID: {
22
+ type: DataTypes.UUID,
23
+ allowNull: false,
24
+ references: {
25
+ model: 'ProductVariant',
26
+ key: 'ProductVariantID'
27
+ },
28
+ onDelete: 'RESTRICT',
29
+ onUpdate: 'CASCADE'
30
+ },
31
+ CustomerID: {
32
+ type: DataTypes.UUID,
33
+ allowNull: false,
34
+ references: {
35
+ model: 'Customer',
36
+ key: 'CustomerID'
37
+ },
38
+ onDelete: 'RESTRICT',
39
+ onUpdate: 'CASCADE'
40
+ },
41
+ CreatedBy: {
42
+ type: DataTypes.UUID,
43
+ allowNull: false
44
+ },
45
+ CreatedAt: {
46
+ type: DataTypes.DATE,
47
+ allowNull: false,
48
+ defaultValue: DataTypes.NOW
49
+ },
50
+ UpdatedBy: {
51
+ type: DataTypes.UUID,
52
+ allowNull: false
53
+ },
54
+ UpdatedAt: {
55
+ type: DataTypes.DATE,
56
+ allowNull: false,
57
+ defaultValue: DataTypes.NOW
58
+ }
59
+ }, {
60
+ tableName: 'WishList',
61
+ timestamps: false
62
+ });
63
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@b2y/ecommerce-common",
3
+ "version": "1.0.0",
4
+ "description": "E-commerce common library",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/yuvakrishna29/ecommerce-common.git"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "author": "Shikha",
17
+ "license": "ISC",
18
+ "bugs": {
19
+ "url": "https://github.com/yuvakrishna29/ecommerce-common/issues"
20
+ },
21
+ "homepage": "https://github.com/yuvakrishna29/ecommerce-common#readme",
22
+ "dependencies": {
23
+ "exceljs": "^4.4.0",
24
+ "luxon": "^3.7.2",
25
+ "razorpay": "^2.9.6"
26
+ }
27
+ }
@@ -0,0 +1,58 @@
1
+ const BooleanEnum = require('../enum/BooleanEnum');
2
+ const AppUtil = {
3
+ generateResponse: function (statusCode, status, message, payload, res, customCode = null) {
4
+ let response = {
5
+ status,
6
+ };
7
+ if (
8
+ payload &&
9
+ (Array.isArray(payload) || Object.keys(payload).length > 0)
10
+ ) {
11
+ if (payload.rows && typeof payload.count !== "undefined") {
12
+ const { rows, count, pageNumber, limit } = payload;
13
+ const currentPage = Number(pageNumber) || 1;
14
+ const pageSize = Number(limit) || count;
15
+ const totalPages = Math.ceil(count / pageSize);
16
+ response.data = rows;
17
+ response.pagination = {
18
+ totalRecords: count,
19
+ totalPages,
20
+ currentPage,
21
+ pageSize,
22
+ hasNext: currentPage < totalPages,
23
+ hasPrev: currentPage > 1,
24
+ };
25
+ } else {
26
+ // Non-paginated response
27
+ response.data = payload;
28
+ }
29
+ }
30
+ if (message) {
31
+ // No data => return message (POST/PUT/DELETE-like APIs)
32
+ response.message = message || "";
33
+ }
34
+ // if custome code also need to send in reponse body
35
+ if (customCode) {
36
+ response.customCode = customCode;
37
+ }
38
+ res.status(statusCode).send(response);
39
+ },
40
+ parseIsActive: function (isActive) {
41
+ if (isActive === true || isActive === "true") return BooleanEnum.TRUE;
42
+ if (isActive === false || isActive === "false") return BooleanEnum.FALSE;
43
+ return undefined;
44
+ },
45
+ getPagination: function (page, size) {
46
+ if (!size || !page) return {};
47
+ const limit = +size;
48
+ const offset = (page - 1) * limit;
49
+ return { limit, offset };
50
+ },
51
+ trimDecimal: function (decimal) {
52
+ const value = parseFloat(decimal);
53
+ return Math.round(value)
54
+ },
55
+ };
56
+
57
+
58
+ module.exports = AppUtil;
@@ -0,0 +1,55 @@
1
+ const AppConstants = require('../constants/AppConstants');
2
+ const {DateTime} = require('luxon');
3
+ const StatusMessage = require('../constants/StatusMessageConstants');
4
+ const DateUtil = {
5
+ isValidDate: function (dateStr) {
6
+ const dt = DateTime.fromISO(dateStr);
7
+ return dt.isValid;
8
+ },
9
+ getDateRange: function (startDate, endDate, logger) {
10
+ let currentStartDate, currentEndDate, previousStartDate, previousEndDate;
11
+ if (startDate && endDate) {
12
+ if (!this.isValidDate(startDate) || !this.isValidDate(endDate)) {
13
+ logger.warn("invalid date format");
14
+ throw new Error(StatusMessage.INVALID_DATE_FORMAT);
15
+ }
16
+ currentStartDate = DateTime.fromISO(startDate, { zone: "utc" });
17
+ currentEndDate = DateTime.fromISO(endDate, { zone: "utc" });
18
+ if (currentStartDate > currentEndDate) {
19
+ logger.warn("invalid date range");
20
+ throw new Error(StatusMessage.INVALID_DATE_RANGE);
21
+ }
22
+ const duration = currentEndDate.diff(currentStartDate);
23
+ previousEndDate = currentStartDate;
24
+ previousStartDate = previousEndDate.minus(duration);
25
+ } else if (startDate || endDate) {
26
+ // Only one provided
27
+ logger.warn("start date and date date both required");
28
+ throw new Error(StatusMessage.DATE_RANGE_REQUIRED);
29
+ } else {
30
+ // Default 7 days including today
31
+ currentEndDate = DateTime.utc();
32
+ currentStartDate = currentEndDate.minus({
33
+ days: AppConstants.DASHBOARD_DEFAULT_DAYS - 1,
34
+ });
35
+
36
+ const duration = currentEndDate.diff(currentStartDate);
37
+ previousEndDate = currentStartDate;
38
+ previousStartDate = previousEndDate.minus(duration);
39
+ }
40
+
41
+ return {
42
+ currentStartDate: currentStartDate.toISO(),
43
+ currentEndDate: currentEndDate.toISO(),
44
+ previousStartDate: previousStartDate.toISO(),
45
+ previousEndDate: previousEndDate.toISO(),
46
+ };
47
+ },
48
+ formatDate: function (date) {
49
+ if (!(date instanceof Date)) return null;
50
+ // conver JS date object to luxon date time
51
+ const dt = DateTime.fromJSDate(date);
52
+ return dt.toFormat('dd/MM/yyyy HH:mm:ss');
53
+ }
54
+ };
55
+ module.exports = DateUtil;
@@ -0,0 +1,125 @@
1
+ const ExcelJS = require('exceljs');
2
+ const { EXCEL_METADATA, EXCEL_DEFAULT_THEME } = require("../constants/ReportConstants");
3
+
4
+ class ExcelUtil {
5
+
6
+ // Create workbook with metadata
7
+ static createWorkbook() {
8
+ const workbook = new ExcelJS.Workbook();
9
+ workbook.creator = EXCEL_METADATA.CREATOR;
10
+ workbook.lastModifiedBy = EXCEL_METADATA.LAST_MODIFIED_BY;
11
+ workbook.created = new Date();
12
+ workbook.modified = new Date();
13
+ return workbook;
14
+ }
15
+
16
+ // Safe worksheet name
17
+ static createWorksheet(workbook, sheetName) {
18
+ const cleanSheetName = sheetName
19
+ .replace(/[\\/*[\]:?]/g, "")
20
+ .substring(0, 31);
21
+
22
+ return workbook.addWorksheet(cleanSheetName);
23
+ }
24
+
25
+ // Setup headers using theme from constants
26
+ static setupHeaders(worksheet, headers) {
27
+ worksheet.columns = headers;
28
+
29
+ const headerRow = worksheet.getRow(1);
30
+ headerRow.eachCell(cell => {
31
+ cell.font = {
32
+ bold: true,
33
+ color: { argb: EXCEL_DEFAULT_THEME.HEADER_FONT_COLOR },
34
+ size: 11
35
+ };
36
+ cell.fill = {
37
+ type: "pattern",
38
+ pattern: "solid",
39
+ fgColor: { argb: EXCEL_DEFAULT_THEME.HEADER_FILL_COLOR }
40
+ };
41
+ cell.alignment = { horizontal: "center", vertical: "middle", wrapText: true };
42
+ cell.border = {
43
+ top: { style: "thin" },
44
+ left: { style: "thin" },
45
+ bottom: { style: "thin" },
46
+ right: { style: "thin" }
47
+ };
48
+ });
49
+
50
+ worksheet.views = [{ state: "frozen", ySplit: 1 }];
51
+ }
52
+
53
+ static cleanValue(val) {
54
+ if (val == null) return "";
55
+
56
+ if (typeof val === "string") {
57
+ // eslint-disable-next-line no-control-regex
58
+ return val.replace(/[\x00-\x1F\x7F]/g, "");
59
+ }
60
+
61
+ if (typeof val === "object") {
62
+ return JSON.stringify(val).substring(0, 32767);
63
+ }
64
+
65
+ return val;
66
+ }
67
+
68
+ static cleanRow(row) {
69
+ const clean = {};
70
+ for (let key in row) clean[key] = ExcelUtil.cleanValue(row[key]);
71
+ return clean;
72
+ }
73
+
74
+ static styleDataRows(worksheet) {
75
+ worksheet.eachRow((row, idx) => {
76
+ if (idx !== 1) {
77
+ row.eachCell(cell => {
78
+ const isNumber = typeof cell.value === 'number';
79
+ cell.alignment = { horizontal: isNumber ? 'right' : 'left', vertical: "middle", wrapText: true };
80
+ cell.border = {
81
+ top: { style: "thin" },
82
+ left: { style: "thin" },
83
+ bottom: { style: "thin" },
84
+ right: { style: "thin" }
85
+ };
86
+ });
87
+ }
88
+ });
89
+ }
90
+
91
+ static autoAdjustColumns(worksheet) {
92
+ worksheet.columns.forEach(col => {
93
+ let maxLength = 10;
94
+ col.eachCell({ includeEmpty: true }, cell => {
95
+ const val = cell.value ? cell.value.toString() : "";
96
+ maxLength = Math.max(maxLength, val.length + 2);
97
+ });
98
+ col.width = Math.min(maxLength, 50);
99
+ });
100
+ }
101
+
102
+ static async writeToResponse(workbook, res, filename, logger) {
103
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
104
+ const finalName = `${filename}_${timestamp}.xlsx`;
105
+
106
+ res.setHeader("Content-Disposition", `attachment; filename="${finalName}"`);
107
+ res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
108
+ res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
109
+ res.setHeader("Pragma", "no-cache");
110
+ res.setHeader("Expires", "0");
111
+ res.setHeader("Content-Transfer-Encoding", "binary");
112
+
113
+ try {
114
+ await workbook.xlsx.write(res);
115
+ res.end();
116
+ } catch (err) {
117
+ logger.error("Excel generation error:", err);
118
+ if (!res.headersSent) {
119
+ res.status(500).json({ error: "Excel generation failed" });
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ module.exports = ExcelUtil;
@@ -0,0 +1,86 @@
1
+ class OrderTimeFilterUtil {
2
+ static getDateRange(filter) {
3
+ if (!filter) return null;
4
+
5
+ const today = new Date();
6
+ let startDate, endDate;
7
+
8
+ switch (filter.toLowerCase()) {
9
+ case AppConstants.LAST_30DAYS.toLowerCase():
10
+ startDate = new Date(today);
11
+ startDate.setDate(today.getDate() - 30);
12
+ startDate.setHours(0, 0, 0, 0);
13
+ endDate = new Date(today);
14
+ endDate.setHours(23, 59, 59, 999);
15
+ break;
16
+
17
+ case AppConstants.LAST_6MONTHS.toLowerCase():
18
+ startDate = new Date(today);
19
+ startDate.setMonth(today.getMonth() - 6);
20
+ startDate.setHours(0, 0, 0, 0);
21
+ endDate = new Date(today);
22
+ endDate.setHours(23, 59, 59, 999);
23
+ break;
24
+
25
+ case AppConstants.OLDER.toLowerCase():
26
+ startDate = new Date(1970, 0, 1);
27
+ endDate = new Date(today);
28
+ break;
29
+
30
+ default:
31
+ const year = parseInt(filter);
32
+ if (!isNaN(year)) {
33
+ return this.getYearRange(year);
34
+ }
35
+ return null;
36
+ }
37
+
38
+ return { startDate, endDate };
39
+ }
40
+
41
+ static getYearRange(year) {
42
+ const today = new Date();
43
+ const startDate = new Date(year, 0, 1);
44
+
45
+ if (year === today.getFullYear()) {
46
+ const endDate = new Date(today);
47
+ endDate.setHours(23, 59, 59, 999);
48
+ return { startDate, endDate };
49
+ }
50
+
51
+ return {
52
+ startDate,
53
+ endDate: new Date(year, 11, 31, 23, 59, 59, 999)
54
+ };
55
+ }
56
+
57
+ static isValidFilter(filter) {
58
+ if (!filter) return false;
59
+
60
+ const validFilters = [
61
+ AppConstants.LAST_30DAYS.toLowerCase(),
62
+ AppConstants.LAST_6MONTHS.toLowerCase(),
63
+ AppConstants.OLDER.toLowerCase()
64
+ ];
65
+
66
+ if (validFilters.includes(filter.toLowerCase())) {
67
+ return true;
68
+ }
69
+
70
+ const year = parseInt(filter);
71
+ const currentYear = new Date().getFullYear();
72
+ return !isNaN(year) && year <= currentYear && year;
73
+ }
74
+
75
+ static buildWhereCondition(filter, Sequelize) {
76
+ const dateRange = this.getDateRange(filter);
77
+ if (!dateRange) return null;
78
+
79
+ return {
80
+ [Sequelize.Op.gte]: dateRange.startDate,
81
+ [Sequelize.Op.lte]: dateRange.endDate
82
+ };
83
+ }
84
+
85
+ }
86
+