ojamoto_models 1.0.10 → 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,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,
@@ -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,
@@ -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.10",
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",