ojamoto_models 1.0.9 → 1.0.11

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,39 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.addColumn("users", "cac_verified", {
6
+ type: Sequelize.BOOLEAN,
7
+ allowNull: false,
8
+ defaultValue: false,
9
+ after: "nin_verified",
10
+ comment: "Business sellers only",
11
+ });
12
+
13
+ await queryInterface.addColumn("kyc_verifications", "cac_data_json", {
14
+ type: Sequelize.JSON,
15
+ allowNull: true,
16
+ after: "bank_data_json",
17
+ comment: "Raw CAC API response from provider",
18
+ });
19
+
20
+ await queryInterface.addColumn(
21
+ "kyc_verifications",
22
+ "verification_attempts",
23
+ {
24
+ type: Sequelize.INTEGER,
25
+ allowNull: false,
26
+ defaultValue: 0,
27
+ after: "cac_data_json",
28
+ },
29
+ );
30
+ },
31
+ async down(queryInterface) {
32
+ await queryInterface.removeColumn("users", "cac_verified");
33
+ await queryInterface.removeColumn("kyc_verifications", "cac_data_json");
34
+ await queryInterface.removeColumn(
35
+ "kyc_verifications",
36
+ "verification_attempts",
37
+ );
38
+ },
39
+ };
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+
3
+ const { SELLER_TIER } = require("../services/constants");
4
+
5
+ module.exports = {
6
+ async up(queryInterface, Sequelize) {
7
+ // seller tiers
8
+ await queryInterface.addColumn("seller_profiles", "tier", {
9
+ type: Sequelize.ENUM(...Object.values(SELLER_TIER)),
10
+ allowNull: true,
11
+ defaultValue: SELLER_TIER.TIER_1,
12
+ after: "verification_status",
13
+ });
14
+
15
+ // escrow units + fee snapshot
16
+ await queryInterface.addColumn("escrows", "units", {
17
+ type: Sequelize.INTEGER,
18
+ allowNull: true,
19
+ defaultValue: 1,
20
+ after: "currency",
21
+ });
22
+
23
+ await queryInterface.addColumn("escrows", "unit_price", {
24
+ type: Sequelize.DECIMAL(15, 2),
25
+ allowNull: true,
26
+ defaultValue: 0.0,
27
+ after: "units",
28
+ comment: "Price per unit at time of order",
29
+ });
30
+
31
+ await queryInterface.addColumn("escrows", "fee_percentage_applied", {
32
+ type: Sequelize.DECIMAL(5, 4),
33
+ allowNull: true,
34
+ defaultValue: 0.05,
35
+ after: "unit_price",
36
+ comment: "Seller's tier fee rate frozen at order time",
37
+ });
38
+
39
+ // funding fee — what the user was actually charged vs what we credit
40
+ await queryInterface.addColumn("wallet_transactions", "charged_amount", {
41
+ type: Sequelize.DECIMAL(15, 2),
42
+ allowNull: true,
43
+ after: "currency",
44
+ comment:
45
+ "Gross amount charged at the gateway (amount + funding fee) - deposits only",
46
+ });
47
+
48
+ await queryInterface.addColumn("wallet_transactions", "funding_fee", {
49
+ type: Sequelize.DECIMAL(15, 2),
50
+ allowNull: true,
51
+ after: "charged_amount",
52
+ });
53
+
54
+ // PIN lockout
55
+ await queryInterface.addColumn("users", "pin_failed_attempts", {
56
+ type: Sequelize.INTEGER,
57
+ allowNull: true,
58
+ defaultValue: 0,
59
+ after: "transaction_pin_hash",
60
+ });
61
+
62
+ await queryInterface.addColumn("users", "pin_locked_until", {
63
+ type: Sequelize.DATE,
64
+ allowNull: true,
65
+ after: "pin_failed_attempts",
66
+ });
67
+
68
+ await queryInterface.addColumn("users", "pin_locked_permanently", {
69
+ type: Sequelize.BOOLEAN,
70
+ allowNull: true,
71
+ defaultValue: false,
72
+ after: "pin_locked_until",
73
+ });
74
+ },
75
+
76
+ async down(queryInterface) {
77
+ await queryInterface.removeColumn("seller_profiles", "tier");
78
+ await queryInterface.removeColumn("escrows", "units");
79
+ await queryInterface.removeColumn("escrows", "unit_price");
80
+ await queryInterface.removeColumn("escrows", "fee_percentage_applied");
81
+ await queryInterface.removeColumn("wallet_transactions", "charged_amount");
82
+ await queryInterface.removeColumn("wallet_transactions", "funding_fee");
83
+ await queryInterface.removeColumn("users", "pin_failed_attempts");
84
+ await queryInterface.removeColumn("users", "pin_locked_until");
85
+ await queryInterface.removeColumn("users", "pin_locked_permanently");
86
+ },
87
+ };
package/models/Escrow.js CHANGED
@@ -84,6 +84,24 @@ module.exports = (sequelize) => {
84
84
  allowNull: false,
85
85
  defaultValue: "NGN",
86
86
  },
87
+ units: {
88
+ type: DataTypes.INTEGER,
89
+ allowNull: false,
90
+ defaultValue: 1,
91
+ },
92
+ unit_price: {
93
+ type: DataTypes.DECIMAL(15, 2),
94
+ allowNull: false,
95
+ defaultValue: 0.0,
96
+ comment: "Price per unit at time of order. Amount = unit_price * units",
97
+ },
98
+ fee_percentage_applied: {
99
+ type: DataTypes.DECIMAL(15, 2),
100
+ allowNull: false,
101
+ defaultValue: 0.05,
102
+ comment:
103
+ "Fee rate determined by seller's tier. 5% - T1, 4.5% - T2, 4% - T3",
104
+ },
87
105
  status: {
88
106
  type: DataTypes.ENUM(...Object.values(ESCROW_STATUS)),
89
107
  allowNull: false,
@@ -37,6 +37,15 @@ module.exports = (sequelize) => {
37
37
  allowNull: true,
38
38
  comment: "Resolved account name and bank details",
39
39
  },
40
+ cac_data_json: {
41
+ type: DataTypes.JSON,
42
+ allowNull: true,
43
+ },
44
+ verification_attempts: {
45
+ type: DataTypes.INTEGER,
46
+ allowNull: false,
47
+ defaultValue: 0,
48
+ },
40
49
  verification_status: {
41
50
  type: DataTypes.ENUM(...Object.values(KYC_STATUS)),
42
51
  allowNull: false,
@@ -4,6 +4,7 @@ const { Model, DataTypes } = require("sequelize");
4
4
  const {
5
5
  SELLER_VERIFICATION_STATUS,
6
6
  SELLER_TYPE,
7
+ SELLER_TIER,
7
8
  } = require("../services/constants");
8
9
 
9
10
  module.exports = (sequelize) => {
@@ -76,6 +77,11 @@ module.exports = (sequelize) => {
76
77
  allowNull: false,
77
78
  defaultValue: SELLER_VERIFICATION_STATUS.UNVERIFIED,
78
79
  },
80
+ tier: {
81
+ type: DataTypes.ENUM(...Object.values(SELLER_TIER)),
82
+ allowNull: false,
83
+ defaultValue: SELLER_TIER.TIER_1,
84
+ },
79
85
  },
80
86
  {
81
87
  sequelize,
package/models/User.js CHANGED
@@ -160,6 +160,20 @@ module.exports = (sequelize) => {
160
160
  type: DataTypes.STRING(255),
161
161
  allowNull: true,
162
162
  },
163
+ pin_failed_attempts: {
164
+ type: DataTypes.INTEGER,
165
+ allowNull: false,
166
+ defaultValue: 0,
167
+ },
168
+ pin_locked_until: {
169
+ type: DataTypes.DATE,
170
+ allowNull: true,
171
+ },
172
+ pin_locked_permanently: {
173
+ type: DataTypes.BOOLEAN,
174
+ allowNull: false,
175
+ defaultValue: false,
176
+ },
163
177
  is_transaction_pin_set: {
164
178
  type: DataTypes.BOOLEAN,
165
179
  defaultValue: false,
@@ -184,7 +198,13 @@ module.exports = (sequelize) => {
184
198
  nin_verified: {
185
199
  type: DataTypes.BOOLEAN,
186
200
  defaultValue: false,
187
- comment: "Sellers only",
201
+ comment: "Buyers and Individual Sellers",
202
+ },
203
+ cac_verified: {
204
+ type: DataTypes.BOOLEAN,
205
+ allowNull: false,
206
+ defaultValue: false,
207
+ comment: "Business sellers only",
188
208
  },
189
209
  bank_verified: {
190
210
  type: DataTypes.BOOLEAN,
@@ -58,6 +58,16 @@ module.exports = (sequelize) => {
58
58
  allowNull: false,
59
59
  defaultValue: "NGN",
60
60
  },
61
+ charged_amount: {
62
+ type: DataTypes.DECIMAL(15, 2),
63
+ allowNull: true,
64
+ comment:
65
+ "Gross amount charged at the gateway (amount + funding fee) - deposits only",
66
+ },
67
+ funding_fee: {
68
+ type: DataTypes.DECIMAL(15, 2),
69
+ allowNull: true,
70
+ },
61
71
  reference: {
62
72
  type: DataTypes.STRING(100),
63
73
  allowNull: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ojamoto_models",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "migrate:up": "npx sequelize-cli db:migrate",
@@ -32,6 +32,8 @@ module.exports = {
32
32
  SELLER_BADGE: {
33
33
  TOP_RATED: "TOP_RATED",
34
34
  TRUSTED_SELLER: "TRUSTED_SELLER",
35
+ VERIFIED_SELLER: "VERIFIED_SELLER",
36
+ PREMIUM_SELLER: "PREMIUM_SELLER",
35
37
  },
36
38
 
37
39
  // - addresses.label ───────────────────────────────────────────────────────────
@@ -76,6 +78,27 @@ module.exports = {
76
78
  SUSPENDED: "SUSPENDED",
77
79
  },
78
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
+ PIN_LOCK: {
98
+ MAX_ATTEMPTS_BEFORE_LOCK: 3,
99
+ LOCK_DURATION_HOURS: 24,
100
+ },
101
+
79
102
  // - products.condition ───────────────────────────────────────────────────
80
103
  PRODUCT_CONDITION: {
81
104
  NEW: "NEW",