ojamoto_models 1.0.13 → 1.0.15

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.
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable("phone_verification_otps", {
6
+ phone_verification_otp_id: {
7
+ type: Sequelize.INTEGER,
8
+ primaryKey: true,
9
+ autoIncrement: true,
10
+ allowNull: false,
11
+ },
12
+ user_id: {
13
+ type: Sequelize.INTEGER,
14
+ allowNull: false,
15
+ unique: true,
16
+ references: { model: "users", key: "user_id" },
17
+ onDelete: "CASCADE",
18
+ onUpdate: "CASCADE",
19
+ },
20
+ otp: {
21
+ type: Sequelize.STRING,
22
+ allowNull: false,
23
+ comment: "Hashed before storage",
24
+ },
25
+ expires_at: {
26
+ type: Sequelize.DATE,
27
+ allowNull: false,
28
+ },
29
+ verification_attempts: {
30
+ type: Sequelize.INTEGER,
31
+ allowNull: false,
32
+ defaultValue: 0,
33
+ },
34
+ created_at: {
35
+ type: Sequelize.DATE,
36
+ allowNull: false,
37
+ },
38
+ updated_at: {
39
+ type: Sequelize.DATE,
40
+ allowNull: false,
41
+ },
42
+ });
43
+ },
44
+ async down(queryInterface) {
45
+ await queryInterface.dropTable("phone_verification_otps");
46
+ },
47
+ };
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable("banks", {
6
+ bank_id: {
7
+ type: Sequelize.INTEGER,
8
+ primaryKey: true,
9
+ autoIncrement: true,
10
+ allowNull: false,
11
+ },
12
+ provider_bank_id: {
13
+ type: Sequelize.INTEGER,
14
+ allowNull: false,
15
+ unique: true,
16
+ comment: "Flutterwave's own bank ID",
17
+ },
18
+ bank_name: {
19
+ type: Sequelize.STRING(150),
20
+ allowNull: false,
21
+ },
22
+ bank_code: {
23
+ type: Sequelize.STRING(20),
24
+ allowNull: false,
25
+ unique: true,
26
+ },
27
+ country: {
28
+ type: Sequelize.STRING(2),
29
+ allowNull: false,
30
+ defaultValue: "NG",
31
+ },
32
+ is_active: {
33
+ type: Sequelize.BOOLEAN,
34
+ allowNull: false,
35
+ defaultValue: true,
36
+ },
37
+ created_at: {
38
+ type: Sequelize.DATE,
39
+ allowNull: false,
40
+ },
41
+ updated_at: {
42
+ type: Sequelize.DATE,
43
+ allowNull: false,
44
+ },
45
+ });
46
+ },
47
+
48
+ async down(queryInterface) {
49
+ await queryInterface.dropTable("banks");
50
+ },
51
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable("user_bank_accounts", {
6
+ user_bank_account_id: {
7
+ type: Sequelize.INTEGER,
8
+ primaryKey: true,
9
+ autoIncrement: true,
10
+ allowNull: false,
11
+ },
12
+ user_id: {
13
+ type: Sequelize.INTEGER,
14
+ allowNull: false,
15
+ unique: true,
16
+ references: { model: "users", key: "user_id" },
17
+ onDelete: "CASCADE",
18
+ onUpdate: "CASCADE",
19
+ comment: "One verified payout account per user",
20
+ },
21
+ bank_id: {
22
+ type: Sequelize.INTEGER,
23
+ allowNull: false,
24
+ references: { model: "banks", key: "bank_id" },
25
+ onDelete: "RESTRICT",
26
+ onUpdate: "CASCADE",
27
+ },
28
+ account_number: {
29
+ type: Sequelize.STRING(20),
30
+ allowNull: false,
31
+ },
32
+ account_name: {
33
+ type: Sequelize.STRING(150),
34
+ allowNull: false,
35
+ comment: "Name returned by the resolve API — used for the match check",
36
+ },
37
+ verified_at: {
38
+ type: Sequelize.DATE,
39
+ allowNull: false,
40
+ },
41
+ created_at: {
42
+ type: Sequelize.DATE,
43
+ allowNull: false,
44
+ },
45
+ updated_at: {
46
+ type: Sequelize.DATE,
47
+ allowNull: false,
48
+ },
49
+ });
50
+ },
51
+ async down(queryInterface) {
52
+ await queryInterface.dropTable("user_bank_accounts");
53
+ },
54
+ };
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable("product_ratings", {
6
+ product_rating_id: {
7
+ type: Sequelize.INTEGER,
8
+ primaryKey: true,
9
+ autoIncrement: true,
10
+ allowNull: false,
11
+ },
12
+ product_id: {
13
+ type: Sequelize.INTEGER,
14
+ allowNull: false,
15
+ references: { model: "products", key: "product_id" },
16
+ onDelete: "CASCADE",
17
+ onUpdate: "CASCADE",
18
+ },
19
+ buyer_id: {
20
+ type: Sequelize.INTEGER,
21
+ allowNull: false,
22
+ references: { model: "users", key: "user_id" },
23
+ onDelete: "CASCADE",
24
+ onUpdate: "CASCADE",
25
+ },
26
+ rating: {
27
+ type: Sequelize.TINYINT,
28
+ allowNull: false,
29
+ },
30
+ comment: {
31
+ type: Sequelize.TEXT,
32
+ allowNull: true,
33
+ },
34
+ created_at: {
35
+ type: Sequelize.DATE,
36
+ allowNull: false,
37
+ },
38
+ updated_at: {
39
+ type: Sequelize.DATE,
40
+ allowNull: false,
41
+ },
42
+ });
43
+
44
+ // Add to Product table
45
+ await queryInterface.addColumn("products", "avg_rating", {
46
+ type: Sequelize.DECIMAL(3, 2),
47
+ allowNull: true,
48
+ after: "revalidation_prompted_at",
49
+ });
50
+
51
+ await queryInterface.addColumn("products", "ratings_count", {
52
+ type: Sequelize.INTEGER,
53
+ allowNull: false,
54
+ defaultValue: 0,
55
+ after: "avg_rating",
56
+ });
57
+
58
+ await queryInterface.addIndex("product_ratings", ["product_id"]);
59
+
60
+ await queryInterface.addIndex(
61
+ "product_ratings",
62
+ ["product_id", "buyer_id"],
63
+ {
64
+ unique: true,
65
+ name: "product_ratings_product_buyer_unique",
66
+ },
67
+ );
68
+ },
69
+
70
+ async down(queryInterface) {
71
+ await queryInterface.dropTable("product_ratings");
72
+ },
73
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable("notification_preferences", {
6
+ notification_preference_id: {
7
+ type: Sequelize.INTEGER,
8
+ primaryKey: true,
9
+ autoIncrement: true,
10
+ allowNull: false,
11
+ },
12
+ user_id: {
13
+ type: Sequelize.INTEGER,
14
+ allowNull: false,
15
+ unique: true,
16
+ references: { model: "users", key: "user_id" },
17
+ onDelete: "CASCADE",
18
+ onUpdate: "CASCADE",
19
+ },
20
+ push_enabled: {
21
+ type: Sequelize.BOOLEAN,
22
+ allowNull: false,
23
+ defaultValue: true,
24
+ },
25
+ in_app_enabled: {
26
+ type: Sequelize.BOOLEAN,
27
+ allowNull: false,
28
+ defaultValue: true,
29
+ },
30
+ email_enabled: {
31
+ type: Sequelize.BOOLEAN,
32
+ allowNull: false,
33
+ defaultValue: true,
34
+ },
35
+ sms_enabled: {
36
+ type: Sequelize.BOOLEAN,
37
+ allowNull: false,
38
+ defaultValue: true,
39
+ },
40
+ created_at: {
41
+ type: Sequelize.DATE,
42
+ allowNull: false,
43
+ },
44
+ updated_at: {
45
+ type: Sequelize.DATE,
46
+ allowNull: false,
47
+ },
48
+ });
49
+ },
50
+
51
+ async down(queryInterface) {
52
+ await queryInterface.dropTable("notification_preferences");
53
+ },
54
+ };
package/models/Bank.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ module.exports = (sequelize) => {
5
+ class Bank extends Model {
6
+ static associate() {}
7
+ }
8
+
9
+ Bank.init(
10
+ {
11
+ bank_id: {
12
+ type: DataTypes.INTEGER,
13
+ primaryKey: true,
14
+ autoIncrement: true,
15
+ },
16
+ provider_bank_id: {
17
+ type: DataTypes.INTEGER,
18
+ allowNull: false,
19
+ unique: true,
20
+ },
21
+ bank_name: {
22
+ type: DataTypes.STRING(150),
23
+ allowNull: false,
24
+ },
25
+ bank_code: {
26
+ type: DataTypes.STRING(20),
27
+ allowNull: false,
28
+ unique: true,
29
+ },
30
+ country: {
31
+ type: DataTypes.STRING(2),
32
+ allowNull: false,
33
+ defaultValue: "NG",
34
+ },
35
+ is_active: {
36
+ type: DataTypes.BOOLEAN,
37
+ allowNull: false,
38
+ defaultValue: true,
39
+ },
40
+ },
41
+ {
42
+ sequelize,
43
+ modelName: "Bank",
44
+ tableName: "banks",
45
+ timestamps: true,
46
+ createdAt: "created_at",
47
+ updatedAt: "updated_at",
48
+ },
49
+ );
50
+
51
+ Bank.removeAttribute("id");
52
+ return Bank;
53
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ module.exports = (sequelize) => {
5
+ class NotificationPreference extends Model {
6
+ static associate(models) {
7
+ NotificationPreference.belongsTo(models.User, {
8
+ foreignKey: "user_id",
9
+ as: "user",
10
+ });
11
+ }
12
+ }
13
+
14
+ NotificationPreference.init(
15
+ {
16
+ notification_preference_id: {
17
+ type: DataTypes.INTEGER,
18
+ primaryKey: true,
19
+ autoIncrement: true,
20
+ },
21
+ user_id: {
22
+ type: DataTypes.INTEGER,
23
+ allowNull: false,
24
+ unique: true,
25
+ },
26
+ push_enabled: {
27
+ type: DataTypes.BOOLEAN,
28
+ allowNull: false,
29
+ defaultValue: true,
30
+ },
31
+ in_app_enabled: {
32
+ type: DataTypes.BOOLEAN,
33
+ allowNull: false,
34
+ defaultValue: true,
35
+ },
36
+ email_enabled: {
37
+ type: DataTypes.BOOLEAN,
38
+ allowNull: false,
39
+ defaultValue: true,
40
+ },
41
+ sms_enabled: {
42
+ type: DataTypes.BOOLEAN,
43
+ allowNull: false,
44
+ defaultValue: true,
45
+ },
46
+ },
47
+ {
48
+ sequelize,
49
+ modelName: "NotificationPreference",
50
+ tableName: "notification_preferences",
51
+ timestamps: true,
52
+ createdAt: "created_at",
53
+ updatedAt: "updated_at",
54
+ },
55
+ );
56
+
57
+ NotificationPreference.removeAttribute("id");
58
+ return NotificationPreference;
59
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ module.exports = (sequelize) => {
5
+ class PhoneVerificationOtp extends Model {
6
+ static associate(models) {
7
+ PhoneVerificationOtp.belongsTo(models.User, {
8
+ foreignKey: "user_id",
9
+ as: "user",
10
+ });
11
+ }
12
+ }
13
+
14
+ PhoneVerificationOtp.init(
15
+ {
16
+ phone_verification_otp_id: {
17
+ type: DataTypes.INTEGER,
18
+ primaryKey: true,
19
+ autoIncrement: true,
20
+ },
21
+ user_id: {
22
+ type: DataTypes.INTEGER,
23
+ allowNull: false,
24
+ unique: true,
25
+ },
26
+ otp: {
27
+ type: DataTypes.STRING,
28
+ allowNull: false,
29
+ },
30
+ expires_at: {
31
+ type: DataTypes.DATE,
32
+ allowNull: false,
33
+ },
34
+ verification_attempts: {
35
+ type: DataTypes.INTEGER,
36
+ allowNull: false,
37
+ defaultValue: 0,
38
+ },
39
+ },
40
+ {
41
+ sequelize,
42
+ modelName: "PhoneVerificationOtp",
43
+ tableName: "phone_verification_otps",
44
+ timestamps: true,
45
+ createdAt: "created_at",
46
+ updatedAt: "updated_at",
47
+ },
48
+ );
49
+
50
+ PhoneVerificationOtp.removeAttribute("id");
51
+ return PhoneVerificationOtp;
52
+ };
package/models/Product.js CHANGED
@@ -35,6 +35,11 @@ module.exports = (sequelize) => {
35
35
  foreignKey: "product_id",
36
36
  as: "stockAdjustments",
37
37
  });
38
+
39
+ Product.hasMany(models.ProductRating, {
40
+ foreignKey: "product_id",
41
+ as: "productRatings",
42
+ });
38
43
  }
39
44
  }
40
45
 
@@ -139,6 +144,15 @@ module.exports = (sequelize) => {
139
144
  allowNull: true,
140
145
  comment: "Timestamp of the last revalidation prompt",
141
146
  },
147
+ avg_rating: {
148
+ type: DataTypes.DECIMAL(3, 2),
149
+ allowNull: true,
150
+ },
151
+ ratings_count: {
152
+ type: DataTypes.INTEGER,
153
+ allowNull: false,
154
+ defaultValue: 0,
155
+ },
142
156
  },
143
157
  {
144
158
  sequelize,
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ module.exports = (sequelize) => {
5
+ class ProductRating extends Model {
6
+ static associate(models) {
7
+ ProductRating.belongsTo(models.Product, {
8
+ foreignKey: "product_id",
9
+ as: "product",
10
+ });
11
+ ProductRating.belongsTo(models.User, {
12
+ foreignKey: "buyer_id",
13
+ as: "buyer",
14
+ });
15
+ }
16
+ }
17
+
18
+ ProductRating.init(
19
+ {
20
+ product_rating_id: {
21
+ type: DataTypes.INTEGER,
22
+ primaryKey: true,
23
+ autoIncrement: true,
24
+ },
25
+ product_id: {
26
+ type: DataTypes.INTEGER,
27
+ allowNull: false,
28
+ },
29
+ buyer_id: {
30
+ type: DataTypes.INTEGER,
31
+ allowNull: false,
32
+ },
33
+ rating: {
34
+ type: DataTypes.TINYINT,
35
+ allowNull: false,
36
+ },
37
+ comment: {
38
+ type: DataTypes.TEXT,
39
+ allowNull: true,
40
+ },
41
+ },
42
+ {
43
+ sequelize,
44
+ modelName: "ProductRating",
45
+ tableName: "product_ratings",
46
+ timestamps: true,
47
+ createdAt: "created_at",
48
+ updatedAt: "updated_at",
49
+ },
50
+ );
51
+
52
+ ProductRating.removeAttribute("id");
53
+ return ProductRating;
54
+ };
@@ -19,6 +19,11 @@ module.exports = (sequelize) => {
19
19
  foreignKey: "seller_profile_id",
20
20
  as: "badges",
21
21
  });
22
+
23
+ SellerProfile.hasOne(models.SellerSubscription, {
24
+ foreignKey: "seller_profile_id",
25
+ as: "subscription",
26
+ });
22
27
  }
23
28
  }
24
29
 
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+ const {
4
+ SUBSCRIPTION_BILLING_TYPE,
5
+ SUBSCRIPTION_STATUS,
6
+ } = require("../services/constants");
7
+
8
+ module.exports = (sequelize) => {
9
+ class SellerSubscription extends Model {
10
+ static associate(models) {
11
+ SellerSubscription.belongsTo(models.SellerProfile, {
12
+ foreignKey: "seller_profile_id",
13
+ as: "sellerProfile",
14
+ });
15
+ }
16
+ }
17
+
18
+ SellerSubscription.init(
19
+ {
20
+ seller_subscription_id: {
21
+ type: DataTypes.INTEGER,
22
+ primaryKey: true,
23
+ autoIncrement: true,
24
+ },
25
+ seller_profile_id: {
26
+ type: DataTypes.INTEGER,
27
+ allowNull: false,
28
+ references: { model: "seller_profiles", key: "seller_profile_id" },
29
+ onDelete: "CASCADE",
30
+ },
31
+ tier: {
32
+ type: DataTypes.STRING(20),
33
+ allowNull: false,
34
+ },
35
+ billing_type: {
36
+ type: DataTypes.ENUM(...Object.values(SUBSCRIPTION_BILLING_TYPE)),
37
+ allowNull: false,
38
+ },
39
+ status: {
40
+ type: DataTypes.ENUM(...Object.values(SUBSCRIPTION_STATUS)),
41
+ allowNull: false,
42
+ defaultValue: SUBSCRIPTION_STATUS.ACTIVE,
43
+ },
44
+ amount_paid: {
45
+ type: DataTypes.DECIMAL(15, 2),
46
+ allowNull: false,
47
+ },
48
+ next_billing_date: {
49
+ type: DataTypes.DATE,
50
+ allowNull: true,
51
+ comment: "NULL for ONE_TIME — never bills again",
52
+ },
53
+ past_due_since: {
54
+ type: DataTypes.DATE,
55
+ allowNull: true,
56
+ },
57
+ },
58
+ {
59
+ sequelize,
60
+ modelName: "SellerSubscription",
61
+ tableName: "seller_subscriptions",
62
+ timestamps: true,
63
+ createdAt: "created_at",
64
+ updatedAt: "updated_at",
65
+ },
66
+ );
67
+
68
+ SellerSubscription.removeAttribute("id");
69
+ return SellerSubscription;
70
+ };
package/models/User.js CHANGED
@@ -109,6 +109,18 @@ module.exports = (sequelize) => {
109
109
  foreignKey: "user_id",
110
110
  as: "wishlist",
111
111
  });
112
+
113
+ // Bank
114
+ User.hasOne(models.UserBankAccount, {
115
+ foreignKey: "user_id",
116
+ as: "bankAccount",
117
+ });
118
+
119
+ // Notification
120
+ User.hasOne(models.NotificationPreference, {
121
+ foreignKey: "user_id",
122
+ as: "notificationPreference",
123
+ });
112
124
  }
113
125
  }
114
126
 
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ const { Model, DataTypes } = require("sequelize");
3
+
4
+ module.exports = (sequelize) => {
5
+ class UserBankAccount extends Model {
6
+ static associate(models) {
7
+ UserBankAccount.belongsTo(models.User, {
8
+ foreignKey: "user_id",
9
+ as: "user",
10
+ });
11
+ UserBankAccount.belongsTo(models.Bank, {
12
+ foreignKey: "bank_id",
13
+ as: "bank",
14
+ });
15
+ }
16
+ }
17
+
18
+ UserBankAccount.init(
19
+ {
20
+ user_bank_account_id: {
21
+ type: DataTypes.INTEGER,
22
+ primaryKey: true,
23
+ autoIncrement: true,
24
+ },
25
+ user_id: {
26
+ type: DataTypes.INTEGER,
27
+ allowNull: false,
28
+ unique: true,
29
+ },
30
+ bank_id: {
31
+ type: DataTypes.INTEGER,
32
+ allowNull: false,
33
+ },
34
+ account_number: {
35
+ type: DataTypes.STRING(20),
36
+ allowNull: false,
37
+ },
38
+ account_name: {
39
+ type: DataTypes.STRING(150),
40
+ allowNull: false,
41
+ },
42
+ verified_at: {
43
+ type: DataTypes.DATE,
44
+ allowNull: false,
45
+ },
46
+ },
47
+ {
48
+ sequelize,
49
+ modelName: "UserBankAccount",
50
+ tableName: "user_bank_accounts",
51
+ timestamps: true,
52
+ createdAt: "created_at",
53
+ updatedAt: "updated_at",
54
+ },
55
+ );
56
+
57
+ return UserBankAccount;
58
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ojamoto_models",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "migrate:up": "npx sequelize-cli db:migrate",
@@ -1,14 +1,6 @@
1
1
  "use strict";
2
2
 
3
3
  module.exports = {
4
- // - Generic status IDs (legacy support) ──────────────────────────────────
5
- STATUS_ID: {
6
- ACTIVE: 1,
7
- INACTIVE: 2,
8
- DELETED: 3,
9
- BLOCKED: 4,
10
- },
11
-
12
4
  // - users.status ─────────────────────────────────────────────────────────
13
5
  USER_STATUS: {
14
6
  ACTIVE: "ACTIVE",
@@ -22,6 +14,14 @@ module.exports = {
22
14
  SELLER: "SELLER",
23
15
  },
24
16
 
17
+ // - addresses.label ───────────────────────────────────────────────────────────
18
+ ADDRESS_LABEL: {
19
+ HOME: "HOME",
20
+ BUSINESS: "BUSINESS",
21
+ PICKUP: "PICKUP",
22
+ OTHER: "OTHER",
23
+ },
24
+
25
25
  // - seller_profiles.user_type ───────────────────────────────────────────────────────────
26
26
  SELLER_TYPE: {
27
27
  INDIVIDUAL: "INDIVIDUAL",
@@ -36,27 +36,44 @@ module.exports = {
36
36
  PREMIUM_SELLER: "PREMIUM_SELLER",
37
37
  },
38
38
 
39
- // - addresses.label ───────────────────────────────────────────────────────────
40
- ADDRESS_LABEL: {
41
- HOME: "HOME",
42
- BUSINESS: "BUSINESS",
43
- PICKUP: "PICKUP",
44
- OTHER: "OTHER",
39
+ // - seller_profiles.verification_status ──────────────────────────────────
40
+ SELLER_VERIFICATION_STATUS: {
41
+ UNVERIFIED: "UNVERIFIED",
42
+ VERIFIED: "VERIFIED",
43
+ SUSPENDED: "SUSPENDED",
45
44
  },
46
45
 
47
- // - admin_users.role ─────────────────────────────────────────────────────
48
- ADMIN_ROLE: {
49
- SUPPORT_AGENT: "SUPPORT_AGENT",
50
- SENIOR_REVIEWER: "SENIOR_REVIEWER",
51
- SUPER_ADMIN: "SUPER_ADMIN",
46
+ // - seller_profiles.tier ─────────────────────────────────────────────────
47
+ SELLER_TIER: {
48
+ TIER_1: "TIER_1",
49
+ TIER_2: "TIER_2",
50
+ TIER_3: "TIER_3",
52
51
  },
53
52
 
54
- // - admin_users.status ───────────────────────────────────────────────────
55
- ADMIN_STATUS: {
53
+ SELLER_TIER_CONFIG: {
54
+ TIER_1: { fee_percentage: 0.05, listing_limit: 10, requires_kyc: false },
55
+ TIER_2: { fee_percentage: 0.045, listing_limit: 100, requires_kyc: true },
56
+ TIER_3: { fee_percentage: 0.04, listing_limit: null, requires_kyc: true },
57
+ },
58
+
59
+ SELLER_TIER_PRICING: {
60
+ TIER_2: { one_time: 50000, recurring: 5000 },
61
+ TIER_3: { one_time: 100000, recurring: 10000 },
62
+ },
63
+
64
+ SUBSCRIPTION_BILLING_TYPE: {
65
+ ONE_TIME: "ONE_TIME",
66
+ RECURRING: "RECURRING",
67
+ },
68
+
69
+ SUBSCRIPTION_STATUS: {
56
70
  ACTIVE: "ACTIVE",
57
- SUSPENDED: "SUSPENDED",
71
+ PAST_DUE: "PAST_DUE",
72
+ CANCELLED: "CANCELLED",
58
73
  },
59
74
 
75
+ RECURRING_GRACE_PERIOD_DAYS: 3,
76
+
60
77
  // - kyc_verifications.verification_status ────────────────────────────────
61
78
  KYC_STATUS: {
62
79
  PENDING: "PENDING",
@@ -71,34 +88,18 @@ module.exports = {
71
88
  QOREID: "QOREID",
72
89
  },
73
90
 
74
- // - seller_profiles.verification_status ──────────────────────────────────
75
- SELLER_VERIFICATION_STATUS: {
76
- UNVERIFIED: "UNVERIFIED",
77
- VERIFIED: "VERIFIED",
78
- SUSPENDED: "SUSPENDED",
79
- },
80
-
81
- // Wallet funding fee - passed on to the user at top-up time 0.8%
82
- FUNDING_FEE_PERCENTAGE: 0.008,
83
-
84
- // - seller_profiles.tier ─────────────────────────────────────────────────
85
- SELLER_TIER: {
86
- TIER_1: "TIER_1",
87
- TIER_2: "TIER_2",
88
- TIER_3: "TIER_3",
89
- },
90
-
91
- SELLER_TIER_CONFIG: {
92
- TIER_1: { fee_percentage: 0.05, listing_limit: 10, requires_kyc: false },
93
- TIER_2: { fee_percentage: 0.045, listing_limit: 100, requires_kyc: true },
94
- TIER_3: { fee_percentage: 0.04, listing_limit: null, requires_kyc: true },
95
- },
96
-
97
91
  PIN_LOCK: {
98
92
  MAX_ATTEMPTS_BEFORE_LOCK: 3,
99
93
  LOCK_DURATION_HOURS: 24,
100
94
  },
101
95
 
96
+ PHONE_OTP: {
97
+ LENGTH: 6,
98
+ MAX_ATTEMPTS: 3,
99
+ EXPIRY_MINUTES: 10,
100
+ RESEND_COOLDOWN_SECONDS: 60,
101
+ },
102
+
102
103
  // - products.condition ───────────────────────────────────────────────────
103
104
  PRODUCT_CONDITION: {
104
105
  NEW: "NEW",
@@ -114,6 +115,61 @@ module.exports = {
114
115
  REMOVED: "REMOVED",
115
116
  },
116
117
 
118
+ PRODUCT_CATEGORY: {
119
+ ENGINE: "ENGINE",
120
+ TRANSMISSION: "TRANSMISSION",
121
+ BRAKE_SYSTEM: "BRAKE_SYSTEM",
122
+ SUSPENSION_STEERING: "SUSPENSION_STEERING",
123
+ ELECTRICAL_BATTERY: "ELECTRICAL_BATTERY",
124
+ BODY_PARTS: "BODY_PARTS",
125
+ EXHAUST_SYSTEM: "EXHAUST_SYSTEM",
126
+ COOLING_SYSTEM: "COOLING_SYSTEM",
127
+ FUEL_SYSTEM: "FUEL_SYSTEM",
128
+ WHEELS_TYRES: "WHEELS_TYRES",
129
+ INTERIOR_ACCESSORIES: "INTERIOR_ACCESSORIES",
130
+ EXTERIOR_ACCESSORIES: "EXTERIOR_ACCESSORIES",
131
+ LIGHTING: "LIGHTING",
132
+ AC_HEATING: "AC_HEATING",
133
+ FILTERS: "FILTERS",
134
+ BELTS_HOSES: "BELTS_HOSES",
135
+ TOOLS_EQUIPMENT: "TOOLS_EQUIPMENT",
136
+ OILS_FLUIDS: "OILS_FLUIDS",
137
+ OTHERS: "OTHERS",
138
+ },
139
+
140
+ PRODUCT_BRAND: {
141
+ TOYOTA: "TOYOTA",
142
+ HONDA: "HONDA",
143
+ LEXUS: "LEXUS",
144
+ NISSAN: "NISSAN",
145
+ MERCEDES_BENZ: "MERCEDES_BENZ",
146
+ BMW: "BMW",
147
+ FORD: "FORD",
148
+ HYUNDAI: "HYUNDAI",
149
+ KIA: "KIA",
150
+ MAZDA: "MAZDA",
151
+ MITSUBISHI: "MITSUBISHI",
152
+ VOLKSWAGEN: "VOLKSWAGEN",
153
+ PEUGEOT: "PEUGEOT",
154
+ ACURA: "ACURA",
155
+ INFINITI: "INFINITI",
156
+ CHEVROLET: "CHEVROLET",
157
+ LAND_ROVER: "LAND_ROVER",
158
+ JEEP: "JEEP",
159
+ AUDI: "AUDI",
160
+ VOLVO: "VOLVO",
161
+ SUZUKI: "SUZUKI",
162
+ MACK: "MACK",
163
+ SCANIA: "SCANIA",
164
+ MAN: "MAN",
165
+ IVECO: "IVECO",
166
+ DAF: "DAF",
167
+ HOWO: "HOWO",
168
+ BOSCH: "BOSCH",
169
+ DENSO: "DENSO",
170
+ OTHERS: "OTHERS",
171
+ },
172
+
117
173
  // - wallet_transactions.type ─────────────────────────────────────────────
118
174
  WALLET_TRANSACTION_TYPE: {
119
175
  DEPOSIT: "DEPOSIT",
@@ -131,6 +187,9 @@ module.exports = {
131
187
  EXPIRED: "EXPIRED",
132
188
  },
133
189
 
190
+ // Wallet funding fee - passed on to the user at top-up time 0.8%
191
+ FUNDING_FEE_PERCENTAGE: 0.008,
192
+
134
193
  // - escrows.status ───────────────────────────────────────────────────────
135
194
  ESCROW_STATUS: {
136
195
  PENDING: "PENDING",
@@ -179,6 +238,13 @@ module.exports = {
179
238
  DELIVERED: "DELIVERED",
180
239
  },
181
240
 
241
+ // TBD
242
+ LOGISTICS_PROVIDER: {
243
+ GIG: "GIG",
244
+ DHL: "DHL",
245
+ FEDEX: "FedEx",
246
+ },
247
+
182
248
  // - webhook_logs.status ──────────────────────────────────────────────────
183
249
  WEBHOOK_STATUS: {
184
250
  ACCEPTED: "ACCEPTED",
@@ -187,10 +253,43 @@ module.exports = {
187
253
 
188
254
  STOCK_ADJUSTMENT_TYPE: {
189
255
  RESTOCK: "RESTOCK",
256
+ SALE_ONLINE: "SALE_ONLINE",
190
257
  SALE_OFFLINE: "SALE_OFFLINE",
191
258
  DAMAGE: "DAMAGE",
192
259
  CORRECTION: "CORRECTION",
193
260
  BULK_UPDATE: "BULK_UPDATE",
194
261
  OTHER: "OTHER",
195
262
  },
263
+
264
+ BANK_NAME_MATCH_THRESHOLD: 0.8, // 80%
265
+
266
+ NOTIFICATION_PREFERENCE: {
267
+ PUSH_NOTIFICATION: "PUSH_NOTIFICATION",
268
+ IN_APP_NOTIFICATION: "IN_APP_NOTIFICATION",
269
+ EMAIL: "EMAIL",
270
+ SMS: "SMS",
271
+ },
272
+
273
+ ////////////////////////////////////////////////////
274
+
275
+ // - Generic status IDs (legacy support) ──────────────────────────────────
276
+ STATUS_ID: {
277
+ ACTIVE: 1,
278
+ INACTIVE: 2,
279
+ DELETED: 3,
280
+ BLOCKED: 4,
281
+ },
282
+
283
+ // - admin_users.role ─────────────────────────────────────────────────────
284
+ ADMIN_ROLE: {
285
+ SUPPORT_AGENT: "SUPPORT_AGENT",
286
+ SENIOR_REVIEWER: "SENIOR_REVIEWER",
287
+ SUPER_ADMIN: "SUPER_ADMIN",
288
+ },
289
+
290
+ // - admin_users.status ───────────────────────────────────────────────────
291
+ ADMIN_STATUS: {
292
+ ACTIVE: "ACTIVE",
293
+ SUSPENDED: "SUSPENDED",
294
+ },
196
295
  };