@feardread/fear 1.1.4 → 1.2.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.
@@ -1,31 +1,148 @@
1
1
  const Razorpay = require("razorpay");
2
+ const paypal = require("@paypal/checkout-server-sdk");
3
+ const Payment = require("../models/payment");
4
+ const methods = require("./crud");
5
+
2
6
  const instance = new Razorpay({
3
7
  key_id: "rzp_test_HSSeDI22muUrLR",
4
8
  key_secret: "sRO0YkBxvgMg0PvWHJN16Uf7",
5
9
  });
6
10
 
7
- const checkout = async (req, res) => {
8
- const { amount } = req.body;
9
- const option = {
10
- amount: amount * 100,
11
- currency: "INR",
12
- };
13
- const order = await instance.orders.create(option);
14
- res.json({
15
- success: true,
16
- order,
17
- });
11
+ // Razorpay instance
12
+ const razorpayInstance = new Razorpay({
13
+ key_id: "rzp_test_HSSeDI22muUrLR",
14
+ key_secret: "sRO0YkBxvgMg0PvWHJN16Uf7",
15
+ });
16
+
17
+ // PayPal environment setup
18
+ const paypalEnvironment = () => {
19
+ const clientId = process.env.PAYPAL_CLIENT_ID || "YOUR_PAYPAL_CLIENT_ID";
20
+ const clientSecret = process.env.PAYPAL_CLIENT_SECRET || "YOUR_PAYPAL_CLIENT_SECRET";
21
+
22
+ // Use sandbox for testing, live for production
23
+ return new paypal.core.SandboxEnvironment(clientId, clientSecret);
24
+ // For production: return new paypal.core.LiveEnvironment(clientId, clientSecret);
25
+ };
26
+
27
+ const paypalClient = () => {
28
+ return new paypal.core.PayPalHttpClient(paypalEnvironment());
18
29
  };
19
30
 
20
- const paymentVerification = async (req, res) => {
21
- const { razorpayOrderId, razorpayPaymentId } = req.body;
22
- res.json({
23
- razorpayOrderId,
24
- razorpayPaymentId,
25
- });
31
+ exports.checkout = async (req, res) => {
32
+ try {
33
+ const { amount } = req.body;
34
+ const option = {
35
+ amount: amount * 100,
36
+ currency: "INR",
37
+ };
38
+ const order = await razorpayInstance.orders.create(option);
39
+ res.json({
40
+ success: true,
41
+ order,
42
+ });
43
+ } catch (error) {
44
+ res.status(500).json({
45
+ success: false,
46
+ message: "Error creating Razorpay order",
47
+ error: error.message,
48
+ });
49
+ }
26
50
  };
27
51
 
28
- module.exports = {
29
- checkout,
30
- paymentVerification,
52
+ exports.paymentVerification = async (req, res) => {
53
+ try {
54
+ const { razorpayOrderId, razorpayPaymentId, razorpaySignature } = req.body;
55
+
56
+ // Verify signature for security
57
+ const crypto = require("crypto");
58
+ const generatedSignature = crypto
59
+ .createHmac("sha256", "sRO0YkBxvgMg0PvWHJN16Uf7")
60
+ .update(`${razorpayOrderId}|${razorpayPaymentId}`)
61
+ .digest("hex");
62
+
63
+ if (generatedSignature === razorpaySignature) {
64
+ res.json({
65
+ success: true,
66
+ razorpayOrderId,
67
+ razorpayPaymentId,
68
+ verified: true,
69
+ });
70
+ } else {
71
+ res.status(400).json({
72
+ success: false,
73
+ message: "Payment verification failed",
74
+ });
75
+ }
76
+ } catch (error) {
77
+ res.status(500).json({
78
+ success: false,
79
+ message: "Error verifying payment",
80
+ error: error.message,
81
+ });
82
+ }
31
83
  };
84
+
85
+ // ============ PAYPAL METHODS ============
86
+
87
+ const createPayPalOrder = async (req, res) => {
88
+ try {
89
+ const { amount, currency = "USD" } = req.body;
90
+
91
+ const request = new paypal.orders.OrdersCreateRequest();
92
+ request.prefer("return=representation");
93
+ request.requestBody({
94
+ intent: "CAPTURE",
95
+ purchase_units: [{
96
+ amount: {
97
+ currency_code: currency,
98
+ value: amount.toString(),
99
+ },
100
+ }],
101
+ });
102
+
103
+ const order = await paypalClient().execute(request);
104
+
105
+ res.json({
106
+ success: true,
107
+ orderId: order.result.id,
108
+ order: order.result,
109
+ });
110
+ } catch (error) {
111
+ res.status(500).json({
112
+ success: false,
113
+ message: "Error creating PayPal order",
114
+ error: error.message,
115
+ });
116
+ }
117
+ };
118
+
119
+ const capturePayPalOrder = async (req, res) => {
120
+ try {
121
+ const { orderId } = req.body;
122
+
123
+ const request = new paypal.orders.OrdersCaptureRequest(orderId);
124
+ request.requestBody({});
125
+
126
+ const capture = await paypalClient().execute(request);
127
+
128
+ res.json({
129
+ success: true,
130
+ captureId: capture.result.id,
131
+ status: capture.result.status,
132
+ capture: capture.result,
133
+ });
134
+ } catch (error) {
135
+ res.status(500).json({
136
+ success: false,
137
+ message: "Error capturing PayPal order",
138
+ error: error.message,
139
+ });
140
+ }
141
+ };
142
+
143
+ const crud = methods.crudController( Payment );
144
+ for(prop in crud) {
145
+ if(crud.hasOwnProperty(prop)) {
146
+ module.exports[prop] = crud[prop];
147
+ }
148
+ }
package/models/order.js CHANGED
@@ -1,26 +1,152 @@
1
- const mongoose = require("mongoose"); // Erase if already required
1
+ const mongoose = require("mongoose");
2
2
 
3
- // Declare the Schema of the Mongo model
4
- var orderSchema = new mongoose.Schema(
3
+ const orderItemSchema = new mongoose.Schema({
4
+ productId: {
5
+ type: mongoose.Schema.Types.ObjectId,
6
+ ref: "Product",
7
+ required: true,
8
+ },
9
+ name: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ quantity: {
14
+ type: Number,
15
+ required: true,
16
+ min: 1,
17
+ },
18
+ price: {
19
+ type: Number,
20
+ required: true,
21
+ },
22
+ discount: {
23
+ type: Number,
24
+ default: 0,
25
+ },
26
+ tax: {
27
+ type: Number,
28
+ default: 0,
29
+ },
30
+ subtotal: {
31
+ type: Number,
32
+ required: true,
33
+ },
34
+ image: String,
35
+ sku: String,
36
+ attributes: {
37
+ type: Map,
38
+ of: String, // For size, color, etc.
39
+ },
40
+ });
41
+
42
+ const orderSchema = new mongoose.Schema(
5
43
  {
6
- user: {
44
+ orderNumber: {
45
+ type: String,
46
+ unique: true,
47
+ required: true,
48
+ },
49
+ userId: {
7
50
  type: mongoose.Schema.Types.ObjectId,
8
51
  ref: "User",
9
52
  required: true,
53
+ index: true,
54
+ },
55
+ // Order Items
56
+ items: [orderItemSchema],
57
+
58
+ // Pricing
59
+ subtotal: {
60
+ type: Number,
61
+ required: true,
62
+ },
63
+ discount: {
64
+ type: Number,
65
+ default: 0,
66
+ },
67
+ tax: {
68
+ type: Number,
69
+ default: 0,
70
+ },
71
+ shippingCost: {
72
+ type: Number,
73
+ default: 0,
74
+ },
75
+ total: {
76
+ type: Number,
77
+ required: true,
78
+ },
79
+ currency: {
80
+ type: String,
81
+ default: "INR",
82
+ enum: ["INR", "USD", "EUR", "GBP"],
83
+ },
84
+
85
+ // Payment Information
86
+ paymentMethod: {
87
+ type: String,
88
+ enum: ["razorpay", "paypal", "card", "upi", "netbanking", "cod"],
89
+ required: true,
10
90
  },
11
- shippingInfo: {
12
- firstname: {
91
+ paymentStatus: {
92
+ type: String,
93
+ enum: ["pending", "processing", "completed", "failed", "refunded", "partially_refunded"],
94
+ default: "pending",
95
+ index: true,
96
+ },
97
+ paymentDetails: {
98
+ // Razorpay
99
+ razorpayOrderId: String,
100
+ razorpayPaymentId: String,
101
+ razorpaySignature: String,
102
+
103
+ // PayPal
104
+ paypalOrderId: String,
105
+ paypalCaptureId: String,
106
+
107
+ // Common
108
+ transactionId: String,
109
+ paymentMethodId: {
110
+ type: mongoose.Schema.Types.ObjectId,
111
+ ref: "PaymentMethod",
112
+ },
113
+ paidAt: Date,
114
+ },
115
+
116
+ // Order Status
117
+ orderStatus: {
118
+ type: String,
119
+ enum: [
120
+ "pending",
121
+ "confirmed",
122
+ "processing",
123
+ "shipped",
124
+ "out_for_delivery",
125
+ "delivered",
126
+ "cancelled",
127
+ "returned",
128
+ "refunded"
129
+ ],
130
+ default: "pending",
131
+ index: true,
132
+ },
133
+
134
+ // Shipping Information
135
+ shippingAddress: {
136
+ name: {
13
137
  type: String,
14
138
  required: true,
15
139
  },
16
- lastname: {
140
+ phone: {
17
141
  type: String,
18
142
  required: true,
19
143
  },
20
- address: {
144
+ email: String,
145
+ line1: {
21
146
  type: String,
22
147
  required: true,
23
148
  },
149
+ line2: String,
24
150
  city: {
25
151
  type: String,
26
152
  required: true,
@@ -29,60 +155,88 @@ var orderSchema = new mongoose.Schema(
29
155
  type: String,
30
156
  required: true,
31
157
  },
32
- other: {
158
+ postalCode: {
33
159
  type: String,
34
- },
35
- pincode: {
36
- type: Number,
37
160
  required: true,
38
161
  },
39
- },
40
- paymentInfo: {
41
- razorpayOrderId: {
42
- type: String,
43
- required: true,
44
- },
45
- razorpayPaymentId: {
162
+ country: {
46
163
  type: String,
47
164
  required: true,
165
+ default: "IN",
48
166
  },
167
+ landmark: String,
49
168
  },
50
- orderItems: [
169
+
170
+ billingAddress: {
171
+ name: String,
172
+ phone: String,
173
+ email: String,
174
+ line1: String,
175
+ line2: String,
176
+ city: String,
177
+ state: String,
178
+ postalCode: String,
179
+ country: String,
180
+ },
181
+
182
+ // Shipping Details
183
+ shippingProvider: String,
184
+ trackingNumber: String,
185
+ estimatedDeliveryDate: Date,
186
+ actualDeliveryDate: Date,
187
+
188
+ // Status History
189
+ statusHistory: [
51
190
  {
52
- product: {
53
- type: mongoose.Schema.Types.ObjectId,
54
- ref: "Product",
55
- required: true,
191
+ status: String,
192
+ timestamp: {
193
+ type: Date,
194
+ default: Date.now,
56
195
  },
57
- quantity: {
58
- type: Number,
59
- required: true,
60
- },
61
- price: {
62
- type: Number,
63
- required: true,
196
+ note: String,
197
+ updatedBy: {
198
+ type: mongoose.Schema.Types.ObjectId,
199
+ ref: "User",
64
200
  },
65
201
  },
66
202
  ],
67
- paidAt: {
68
- type: Date,
69
- default: Date.now(),
70
- },
71
- month: {
203
+
204
+ // Discount/Coupon
205
+ couponCode: String,
206
+ couponDiscount: {
72
207
  type: Number,
73
- default: new Date().getMonth(),
208
+ default: 0,
74
209
  },
75
- totalPrice: {
76
- type: Number,
77
- required: true,
78
- },
79
- totalPriceAfterDiscount: {
80
- type: Number,
81
- required: true,
210
+
211
+ // Notes
212
+ customerNote: String,
213
+ internalNote: String,
214
+
215
+ // Cancellation/Return
216
+ cancellationReason: String,
217
+ cancelledAt: Date,
218
+ cancelledBy: {
219
+ type: mongoose.Schema.Types.ObjectId,
220
+ ref: "User",
82
221
  },
83
- orderStatus: {
222
+
223
+ returnReason: String,
224
+ returnedAt: Date,
225
+
226
+ // Refund Information
227
+ refundAmount: Number,
228
+ refundStatus: {
84
229
  type: String,
85
- default: "Ordered",
230
+ enum: ["none", "pending", "processing", "completed", "failed"],
231
+ default: "none",
232
+ },
233
+ refundedAt: Date,
234
+ refundTransactionId: String,
235
+
236
+ // Metadata
237
+ metadata: {
238
+ type: Map,
239
+ of: mongoose.Schema.Types.Mixed,
86
240
  },
87
241
  },
88
242
  {
@@ -90,5 +244,150 @@ var orderSchema = new mongoose.Schema(
90
244
  }
91
245
  );
92
246
 
93
- //Export the model
94
- module.exports = mongoose.model("Order", orderSchema);
247
+ // Indexes for better query performance
248
+ orderSchema.index({ orderNumber: 1 });
249
+ orderSchema.index({ userId: 1, createdAt: -1 });
250
+ orderSchema.index({ orderStatus: 1, createdAt: -1 });
251
+ orderSchema.index({ paymentStatus: 1 });
252
+ orderSchema.index({ "paymentDetails.razorpayOrderId": 1 });
253
+ orderSchema.index({ "paymentDetails.paypalOrderId": 1 });
254
+ orderSchema.index({ trackingNumber: 1 });
255
+
256
+ // Pre-save middleware to generate order number
257
+ orderSchema.pre("save", async function (next) {
258
+ if (!this.orderNumber) {
259
+ const timestamp = Date.now().toString(36).toUpperCase();
260
+ const random = Math.random().toString(36).substring(2, 7).toUpperCase();
261
+ this.orderNumber = `ORD-${timestamp}-${random}`;
262
+ }
263
+ next();
264
+ });
265
+
266
+ // Pre-save middleware to add status history
267
+ orderSchema.pre("save", function (next) {
268
+ if (this.isModified("orderStatus")) {
269
+ this.statusHistory.push({
270
+ status: this.orderStatus,
271
+ timestamp: new Date(),
272
+ });
273
+ }
274
+ next();
275
+ });
276
+
277
+ // Static method to get orders by user
278
+ orderSchema.statics.getUserOrders = async function (userId, options = {}) {
279
+ const { status, limit = 10, skip = 0 } = options;
280
+ const query = { userId };
281
+
282
+ if (status) {
283
+ query.orderStatus = status;
284
+ }
285
+
286
+ return await this.find(query)
287
+ .sort({ createdAt: -1 })
288
+ .limit(limit)
289
+ .skip(skip)
290
+ .populate("items.productId", "name images")
291
+ .populate("paymentDetails.paymentMethodId");
292
+ };
293
+
294
+ // Static method to get order statistics
295
+ orderSchema.statics.getOrderStats = async function (userId) {
296
+ const stats = await this.aggregate([
297
+ { $match: { userId: mongoose.Types.ObjectId(userId) } },
298
+ {
299
+ $group: {
300
+ _id: "$orderStatus",
301
+ count: { $sum: 1 },
302
+ totalAmount: { $sum: "$total" },
303
+ },
304
+ },
305
+ ]);
306
+
307
+ return stats;
308
+ };
309
+
310
+ // Instance method to mark as paid
311
+ orderSchema.methods.markAsPaid = async function (paymentInfo) {
312
+ this.paymentStatus = "completed";
313
+ this.paymentDetails = {
314
+ ...this.paymentDetails,
315
+ ...paymentInfo,
316
+ paidAt: new Date(),
317
+ };
318
+ this.orderStatus = "confirmed";
319
+ return await this.save();
320
+ };
321
+
322
+ // Instance method to update order status
323
+ orderSchema.methods.updateStatus = async function (status, note, updatedBy) {
324
+ this.orderStatus = status;
325
+ this.statusHistory.push({
326
+ status,
327
+ timestamp: new Date(),
328
+ note,
329
+ updatedBy,
330
+ });
331
+
332
+ // Update specific dates based on status
333
+ if (status === "delivered") {
334
+ this.actualDeliveryDate = new Date();
335
+ } else if (status === "cancelled") {
336
+ this.cancelledAt = new Date();
337
+ this.cancelledBy = updatedBy;
338
+ } else if (status === "returned") {
339
+ this.returnedAt = new Date();
340
+ }
341
+
342
+ return await this.save();
343
+ };
344
+
345
+ // Instance method to process refund
346
+ orderSchema.methods.processRefund = async function (amount, transactionId) {
347
+ this.refundAmount = amount || this.total;
348
+ this.refundStatus = "completed";
349
+ this.refundedAt = new Date();
350
+ this.refundTransactionId = transactionId;
351
+ this.paymentStatus = amount >= this.total ? "refunded" : "partially_refunded";
352
+ this.orderStatus = "refunded";
353
+ return await this.save();
354
+ };
355
+
356
+ // Instance method to add tracking information
357
+ orderSchema.methods.addTracking = async function (provider, trackingNumber, estimatedDelivery) {
358
+ this.shippingProvider = provider;
359
+ this.trackingNumber = trackingNumber;
360
+ this.estimatedDeliveryDate = estimatedDelivery;
361
+ this.orderStatus = "shipped";
362
+ return await this.save();
363
+ };
364
+
365
+ // Virtual for order age in days
366
+ orderSchema.virtual("orderAge").get(function () {
367
+ return Math.floor((Date.now() - this.createdAt) / (1000 * 60 * 60 * 24));
368
+ });
369
+
370
+ // Virtual for items count
371
+ orderSchema.virtual("itemsCount").get(function () {
372
+ return this.items.reduce((total, item) => total + item.quantity, 0);
373
+ });
374
+
375
+ // Virtual for checking if order can be cancelled
376
+ orderSchema.virtual("canCancel").get(function () {
377
+ return ["pending", "confirmed", "processing"].includes(this.orderStatus);
378
+ });
379
+
380
+ // Virtual for checking if order can be returned
381
+ orderSchema.virtual("canReturn").get(function () {
382
+ const returnWindow = 7; // days
383
+ return (
384
+ this.orderStatus === "delivered" &&
385
+ this.orderAge <= returnWindow
386
+ );
387
+ });
388
+
389
+ // Ensure virtuals are included in JSON
390
+ orderSchema.set("toJSON", { virtuals: true });
391
+ orderSchema.set("toObject", { virtuals: true });
392
+
393
+ module.exports = mongoose.model("Order", orderSchema);
@@ -0,0 +1,198 @@
1
+ const mongoose = require("mongoose");
2
+ const crypto = require("crypto");
3
+
4
+ const paymentMethodSchema = new mongoose.Schema(
5
+ {
6
+ userId: {
7
+ type: mongoose.Schema.Types.ObjectId,
8
+ ref: "User",
9
+ required: true,
10
+ index: true,
11
+ },
12
+ paymentType: {
13
+ type: String,
14
+ enum: ["razorpay", "paypal", "card", "upi", "netbanking"],
15
+ required: true,
16
+ },
17
+ paymentToken: {
18
+ type: String,
19
+ required: true,
20
+ // This stores the tokenized payment method from the payment gateway
21
+ },
22
+ isDefault: {
23
+ type: Boolean,
24
+ default: false,
25
+ },
26
+ isActive: {
27
+ type: Boolean,
28
+ default: true,
29
+ },
30
+ // Card/Payment details (only non-sensitive info for display)
31
+ cardDetails: {
32
+ last4: {
33
+ type: String,
34
+ maxlength: 4,
35
+ },
36
+ brand: {
37
+ type: String, // Visa, Mastercard, Amex, etc.
38
+ },
39
+ expiryMonth: {
40
+ type: String,
41
+ maxlength: 2,
42
+ },
43
+ expiryYear: {
44
+ type: String,
45
+ maxlength: 4,
46
+ },
47
+ cardholderName: {
48
+ type: String,
49
+ },
50
+ fingerprint: {
51
+ type: String, // Unique identifier for the card
52
+ },
53
+ },
54
+ // PayPal details
55
+ paypalDetails: {
56
+ email: {
57
+ type: String,
58
+ },
59
+ payerId: {
60
+ type: String,
61
+ },
62
+ },
63
+ // UPI details
64
+ upiDetails: {
65
+ vpa: {
66
+ type: String, // Virtual Payment Address (e.g., user@paytm)
67
+ },
68
+ },
69
+ // Billing address
70
+ billingAddress: {
71
+ name: String,
72
+ line1: String,
73
+ line2: String,
74
+ city: String,
75
+ state: String,
76
+ postalCode: String,
77
+ country: {
78
+ type: String,
79
+ default: "IN",
80
+ },
81
+ },
82
+ // Metadata for additional information
83
+ metadata: {
84
+ type: Map,
85
+ of: String,
86
+ },
87
+ },
88
+ {
89
+ timestamps: true,
90
+ }
91
+ );
92
+
93
+ // Indexes for better query performance
94
+ paymentMethodSchema.index({ userId: 1, isDefault: 1 });
95
+ paymentMethodSchema.index({ userId: 1, isActive: 1 });
96
+ paymentMethodSchema.index({ createdAt: -1 });
97
+
98
+ // Middleware to ensure only one default payment method per user
99
+ paymentMethodSchema.pre("save", async function (next) {
100
+ if (this.isDefault && this.isModified("isDefault")) {
101
+ // Remove default flag from other payment methods for this user
102
+ await mongoose.model("PaymentMethod").updateMany(
103
+ {
104
+ userId: this.userId,
105
+ _id: { $ne: this._id },
106
+ isDefault: true,
107
+ },
108
+ { isDefault: false }
109
+ );
110
+ }
111
+ next();
112
+ });
113
+ paymentMethodSchema.statics.getDefaultPaymentMethod = async function (userId) {
114
+ return await this.findOne({
115
+ userId,
116
+ isDefault: true,
117
+ isActive: true,
118
+ });
119
+ };
120
+ paymentMethodSchema.statics.getUserPaymentMethods = async function (userId) {
121
+ return await this.find({
122
+ userId,
123
+ isActive: true,
124
+ }).sort({ isDefault: -1, createdAt: -1 });
125
+ };
126
+
127
+ paymentMethodSchema.methods.setAsDefault = async function () {
128
+ await mongoose.model("PaymentMethod").updateMany(
129
+ {
130
+ userId: this.userId,
131
+ _id: { $ne: this._id },
132
+ },
133
+ { isDefault: false }
134
+ );
135
+
136
+ this.isDefault = true;
137
+ return await this.save();
138
+ };
139
+ paymentMethodSchema.methods.softDelete = async function () {
140
+ this.isActive = false;
141
+ if (this.isDefault) {
142
+ this.isDefault = false;
143
+ // Optionally set another method as default
144
+ const otherMethod = await mongoose.model("PaymentMethod").findOne({
145
+ userId: this.userId,
146
+ _id: { $ne: this._id },
147
+ isActive: true,
148
+ });
149
+ if (otherMethod) {
150
+ otherMethod.isDefault = true;
151
+ await otherMethod.save();
152
+ }
153
+ }
154
+ return await this.save();
155
+ };
156
+
157
+ // Virtual for masked card number display
158
+ paymentMethodSchema.virtual("displayNumber").get(function () {
159
+ if (this.cardDetails?.last4) {
160
+ return `•••• •••• •••• ${this.cardDetails.last4}`;
161
+ }
162
+ if (this.paypalDetails?.email) {
163
+ return this.paypalDetails.email;
164
+ }
165
+ if (this.upiDetails?.vpa) {
166
+ return this.upiDetails.vpa;
167
+ }
168
+ return "Payment Method";
169
+ });
170
+
171
+ // Virtual for expiry display
172
+ paymentMethodSchema.virtual("expiryDisplay").get(function () {
173
+ if (this.cardDetails?.expiryMonth && this.cardDetails?.expiryYear) {
174
+ return `${this.cardDetails.expiryMonth}/${this.cardDetails.expiryYear}`;
175
+ }
176
+ return null;
177
+ });
178
+
179
+ // Virtual for checking if card is expired
180
+ paymentMethodSchema.virtual("isExpired").get(function () {
181
+ if (this.cardDetails?.expiryMonth && this.cardDetails?.expiryYear) {
182
+ const now = new Date();
183
+ const expiryDate = new Date(
184
+ parseInt(this.cardDetails.expiryYear),
185
+ parseInt(this.cardDetails.expiryMonth) - 1
186
+ );
187
+ return now > expiryDate;
188
+ }
189
+ return false;
190
+ });
191
+
192
+ // Ensure virtuals are included in JSON
193
+ paymentMethodSchema.set("toJSON", { virtuals: true });
194
+ paymentMethodSchema.set("toObject", { virtuals: true });
195
+
196
+ const PaymentMethod = mongoose.model("PaymentMethod", paymentMethodSchema);
197
+
198
+ module.exports = PaymentMethod;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feardread/fear",
3
- "version": "1.1.4",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,17 @@
1
+ const Payment = require('../controllers/payment');
2
+
3
+ module.exports = (fear) => {
4
+ const router = fear.createRouter();
5
+ const handler = fear.getHandler();
6
+ const validator = fear.getValidator();
7
+
8
+ router.get("/all", Payment.list);
9
+ router.post("/new", Payment.create);
10
+
11
+ router.route('/:id')
12
+ .get(Payment.read)
13
+ .put(Payment.update);
14
+
15
+
16
+ return router;
17
+ }