@churchsoln/dbms 1.0.63 → 1.0.65

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 (26) hide show
  1. package/constants/index.js +47 -0
  2. package/migrations/church/20261017170648-create-vendor.js +46 -0
  3. package/migrations/church/20261017170649-create-bill.js +73 -0
  4. package/migrations/church/20261017170650-create-billLine.js +61 -0
  5. package/migrations/church/20261017170651-create-billAttachment.js +43 -0
  6. package/migrations/church/20261017170652-create-billPayment.js +72 -0
  7. package/migrations/church/20261023090000-create-customer.js +46 -0
  8. package/migrations/church/20261023090001-create-invoice.js +71 -0
  9. package/migrations/church/20261023090002-create-invoiceLine.js +57 -0
  10. package/migrations/church/20261023090003-create-invoicePayment.js +72 -0
  11. package/migrations/church/20261026170653-create-bankReconciliation.js +47 -0
  12. package/migrations/church/20261026170654-update-journalEntryLine-add-reconciliation.js +35 -0
  13. package/models/church/bankReconciliation.js +48 -0
  14. package/models/church/bill.js +83 -0
  15. package/models/church/billAttachment.js +34 -0
  16. package/models/church/billLine.js +47 -0
  17. package/models/church/billPayment.js +48 -0
  18. package/models/church/customer.js +45 -0
  19. package/models/church/invoice.js +75 -0
  20. package/models/church/invoiceLine.js +39 -0
  21. package/models/church/invoicePayment.js +48 -0
  22. package/models/church/journalEntryLine.js +10 -0
  23. package/models/church/vendor.js +45 -0
  24. package/package.json +1 -1
  25. package/seeders/church/20261017170653-chartOfAccounts-accountsPayable.js +44 -0
  26. package/seeders/church/20261023090004-chartOfAccounts-accountsReceivable.js +44 -0
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ module.exports = {
3
+ up: async (queryInterface, DataTypes) => {
4
+ await queryInterface
5
+ .addColumn("JournalEntryLine", "cleared", {
6
+ type: DataTypes.BOOLEAN,
7
+ allowNull: false,
8
+ defaultValue: false,
9
+ })
10
+ .then(() =>
11
+ queryInterface.addColumn("JournalEntryLine", "bankReconciliationId", {
12
+ type: DataTypes.INTEGER,
13
+ allowNull: true,
14
+ })
15
+ )
16
+ .then(() =>
17
+ queryInterface.addConstraint("JournalEntryLine", {
18
+ fields: ["bankReconciliationId"],
19
+ type: "foreign key",
20
+ name: "JournalEntryLine_BankReconciliationId_Fkey",
21
+ references: {
22
+ table: "BankReconciliation",
23
+ field: "id",
24
+ },
25
+ onDelete: "set null",
26
+ onUpdate: "cascade",
27
+ })
28
+ );
29
+ },
30
+ down: async (queryInterface) => {
31
+ await queryInterface.removeConstraint("JournalEntryLine", "JournalEntryLine_BankReconciliationId_Fkey");
32
+ await queryInterface.removeColumn("JournalEntryLine", "bankReconciliationId");
33
+ await queryInterface.removeColumn("JournalEntryLine", "cleared");
34
+ },
35
+ };
@@ -0,0 +1,48 @@
1
+ const { BANK_RECONCILIATION_STATUS } = require("../../constants");
2
+
3
+ module.exports = (sequelize, DataTypes) => {
4
+ const bankReconciliation = sequelize.define(
5
+ "BankReconciliation",
6
+ {
7
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
8
+ chartOfAccountId: { type: DataTypes.INTEGER, allowNull: false },
9
+ statementDate: { type: DataTypes.DATEONLY, allowNull: false },
10
+ statementEndingBalance: { type: DataTypes.DECIMAL(12, 2), allowNull: false },
11
+ beginningBalance: { type: DataTypes.DECIMAL(12, 2), allowNull: false },
12
+ clearedBalance: { type: DataTypes.DECIMAL(12, 2), allowNull: true },
13
+ difference: { type: DataTypes.DECIMAL(12, 2), allowNull: true },
14
+ status: { type: DataTypes.STRING, defaultValue: BANK_RECONCILIATION_STATUS.IN_PROGRESS },
15
+ startedAt: { type: DataTypes.DATE },
16
+ completedAt: { type: DataTypes.DATE, allowNull: true },
17
+ createdBy: { type: DataTypes.INTEGER, allowNull: true },
18
+ createdAt: { type: DataTypes.DATE },
19
+ updatedAt: { type: DataTypes.DATE },
20
+ },
21
+ { freezeTableName: true, timestamps: false }
22
+ );
23
+ bankReconciliation.associate = function (models) {
24
+ bankReconciliation.belongsTo(models.chartOfAccounts, {
25
+ foreignKey: "chartOfAccountId",
26
+ as: "chartOfAccount",
27
+ });
28
+ bankReconciliation.hasMany(models.journalEntryLine, {
29
+ foreignKey: "bankReconciliationId",
30
+ as: "clearedLines",
31
+ });
32
+ };
33
+ bankReconciliation.selectedFields = [
34
+ "id",
35
+ "chartOfAccountId",
36
+ "statementDate",
37
+ "statementEndingBalance",
38
+ "beginningBalance",
39
+ "clearedBalance",
40
+ "difference",
41
+ "status",
42
+ "startedAt",
43
+ "completedAt",
44
+ "createdBy",
45
+ "createdAt",
46
+ ];
47
+ return bankReconciliation;
48
+ };
@@ -0,0 +1,83 @@
1
+ const { BILL_STATUS, BILL_TAX_MODE } = require("../../constants");
2
+
3
+ module.exports = (sequelize, DataTypes) => {
4
+ const bill = sequelize.define(
5
+ "Bill",
6
+ {
7
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
8
+ billNo: { type: DataTypes.STRING, allowNull: false, unique: true },
9
+ vendorId: { type: DataTypes.INTEGER, allowNull: false },
10
+ reference: { type: DataTypes.STRING, allowNull: true },
11
+ description: { type: DataTypes.TEXT, allowNull: true },
12
+ billDate: { type: DataTypes.DATEONLY, allowNull: true },
13
+ dueDate: { type: DataTypes.DATEONLY, allowNull: true },
14
+ terms: { type: DataTypes.STRING, allowNull: true },
15
+ currency: { type: DataTypes.STRING, defaultValue: "USD" },
16
+ memo: { type: DataTypes.TEXT, allowNull: true },
17
+ notes: { type: DataTypes.TEXT, allowNull: true },
18
+ status: { type: DataTypes.STRING, defaultValue: BILL_STATUS.DRAFT },
19
+ taxMode: { type: DataTypes.STRING, defaultValue: BILL_TAX_MODE.EXCLUSIVE },
20
+ subtotal: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
21
+ tax: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
22
+ discount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
23
+ amount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
24
+ amountPaid: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
25
+ amountDue: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
26
+ paidDate: { type: DataTypes.DATEONLY, allowNull: true },
27
+ journalEntryId: { type: DataTypes.INTEGER, allowNull: true },
28
+ createdBy: { type: DataTypes.INTEGER, allowNull: true },
29
+ createdAt: { type: DataTypes.DATE },
30
+ updatedAt: { type: DataTypes.DATE },
31
+ },
32
+ { freezeTableName: true, timestamps: false }
33
+ );
34
+ bill.associate = function (models) {
35
+ bill.belongsTo(models.vendor, {
36
+ foreignKey: "vendorId",
37
+ as: "vendor",
38
+ });
39
+ bill.belongsTo(models.journalEntry, {
40
+ foreignKey: "journalEntryId",
41
+ as: "journalEntry",
42
+ });
43
+ bill.hasMany(models.billLine, {
44
+ foreignKey: "billId",
45
+ as: "billLines",
46
+ });
47
+ bill.hasMany(models.billAttachment, {
48
+ foreignKey: "billId",
49
+ as: "billAttachments",
50
+ });
51
+ bill.hasMany(models.billPayment, {
52
+ foreignKey: "billId",
53
+ as: "billPayments",
54
+ });
55
+ };
56
+ bill.selectedFields = [
57
+ "id",
58
+ "billNo",
59
+ "vendorId",
60
+ "reference",
61
+ "description",
62
+ "billDate",
63
+ "dueDate",
64
+ "terms",
65
+ "currency",
66
+ "memo",
67
+ "notes",
68
+ "status",
69
+ "taxMode",
70
+ "subtotal",
71
+ "tax",
72
+ "discount",
73
+ "amount",
74
+ "amountPaid",
75
+ "amountDue",
76
+ "paidDate",
77
+ "journalEntryId",
78
+ "createdBy",
79
+ "createdAt",
80
+ "updatedAt",
81
+ ];
82
+ return bill;
83
+ };
@@ -0,0 +1,34 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const billAttachment = sequelize.define(
3
+ "BillAttachment",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ billId: { type: DataTypes.INTEGER, allowNull: false },
7
+ name: { type: DataTypes.STRING, allowNull: false },
8
+ fileName: { type: DataTypes.STRING, allowNull: false },
9
+ url: { type: DataTypes.STRING, allowNull: false },
10
+ mimeType: { type: DataTypes.STRING, allowNull: true },
11
+ size: { type: DataTypes.INTEGER, allowNull: true },
12
+ createdAt: { type: DataTypes.DATE },
13
+ updatedAt: { type: DataTypes.DATE },
14
+ },
15
+ { freezeTableName: true, timestamps: false }
16
+ );
17
+ billAttachment.associate = function (models) {
18
+ billAttachment.belongsTo(models.bill, {
19
+ foreignKey: "billId",
20
+ as: "bill",
21
+ });
22
+ };
23
+ billAttachment.selectedFields = [
24
+ "id",
25
+ "billId",
26
+ "name",
27
+ "fileName",
28
+ "url",
29
+ "mimeType",
30
+ "size",
31
+ "createdAt",
32
+ ];
33
+ return billAttachment;
34
+ };
@@ -0,0 +1,47 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const billLine = sequelize.define(
3
+ "BillLine",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ billId: { type: DataTypes.INTEGER, allowNull: false },
7
+ chartOfAccountId: { type: DataTypes.INTEGER, allowNull: true },
8
+ description: { type: DataTypes.TEXT, allowNull: true },
9
+ className: { type: DataTypes.STRING, allowNull: true },
10
+ amount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
11
+ taxRate: { type: DataTypes.DECIMAL(6, 4), defaultValue: 0 },
12
+ taxLabel: { type: DataTypes.STRING, allowNull: true },
13
+ netAmount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
14
+ taxAmount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
15
+ total: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
16
+ sortOrder: { type: DataTypes.INTEGER, defaultValue: 0 },
17
+ createdAt: { type: DataTypes.DATE },
18
+ updatedAt: { type: DataTypes.DATE },
19
+ },
20
+ { freezeTableName: true, timestamps: false }
21
+ );
22
+ billLine.associate = function (models) {
23
+ billLine.belongsTo(models.bill, {
24
+ foreignKey: "billId",
25
+ as: "bill",
26
+ });
27
+ billLine.belongsTo(models.chartOfAccounts, {
28
+ foreignKey: "chartOfAccountId",
29
+ as: "chartOfAccount",
30
+ });
31
+ };
32
+ billLine.selectedFields = [
33
+ "id",
34
+ "billId",
35
+ "chartOfAccountId",
36
+ "description",
37
+ "className",
38
+ "amount",
39
+ "taxRate",
40
+ "taxLabel",
41
+ "netAmount",
42
+ "taxAmount",
43
+ "total",
44
+ "sortOrder",
45
+ ];
46
+ return billLine;
47
+ };
@@ -0,0 +1,48 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const billPayment = sequelize.define(
3
+ "BillPayment",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ billId: { type: DataTypes.INTEGER, allowNull: false },
7
+ paymentDate: { type: DataTypes.DATEONLY, allowNull: false },
8
+ amount: { type: DataTypes.DECIMAL(12, 2), allowNull: false },
9
+ paidFromAccountId: { type: DataTypes.INTEGER, allowNull: false },
10
+ method: { type: DataTypes.STRING, allowNull: true },
11
+ reference: { type: DataTypes.STRING, allowNull: true },
12
+ memo: { type: DataTypes.TEXT, allowNull: true },
13
+ journalEntryId: { type: DataTypes.INTEGER, allowNull: true },
14
+ createdBy: { type: DataTypes.INTEGER, allowNull: true },
15
+ createdAt: { type: DataTypes.DATE },
16
+ updatedAt: { type: DataTypes.DATE },
17
+ },
18
+ { freezeTableName: true, timestamps: false }
19
+ );
20
+ billPayment.associate = function (models) {
21
+ billPayment.belongsTo(models.bill, {
22
+ foreignKey: "billId",
23
+ as: "bill",
24
+ });
25
+ billPayment.belongsTo(models.chartOfAccounts, {
26
+ foreignKey: "paidFromAccountId",
27
+ as: "paidFromAccount",
28
+ });
29
+ billPayment.belongsTo(models.journalEntry, {
30
+ foreignKey: "journalEntryId",
31
+ as: "journalEntry",
32
+ });
33
+ };
34
+ billPayment.selectedFields = [
35
+ "id",
36
+ "billId",
37
+ "paymentDate",
38
+ "amount",
39
+ "paidFromAccountId",
40
+ "method",
41
+ "reference",
42
+ "memo",
43
+ "journalEntryId",
44
+ "createdBy",
45
+ "createdAt",
46
+ ];
47
+ return billPayment;
48
+ };
@@ -0,0 +1,45 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const customer = sequelize.define(
3
+ "Customer",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ name: { type: DataTypes.STRING, allowNull: false, unique: true },
7
+ email: { type: DataTypes.STRING, allowNull: true },
8
+ phone: { type: DataTypes.STRING, allowNull: true },
9
+ addressLine1: { type: DataTypes.STRING, allowNull: true },
10
+ addressLine2: { type: DataTypes.STRING, allowNull: true },
11
+ defaultTerms: { type: DataTypes.STRING, allowNull: true },
12
+ defaultChartOfAccountId: { type: DataTypes.INTEGER, allowNull: true },
13
+ notes: { type: DataTypes.TEXT, allowNull: true },
14
+ status: { type: DataTypes.BOOLEAN, defaultValue: true },
15
+ createdAt: { type: DataTypes.DATE },
16
+ updatedAt: { type: DataTypes.DATE },
17
+ },
18
+ { freezeTableName: true, timestamps: false }
19
+ );
20
+ customer.associate = function (models) {
21
+ customer.belongsTo(models.chartOfAccounts, {
22
+ foreignKey: "defaultChartOfAccountId",
23
+ as: "defaultChartOfAccount",
24
+ });
25
+ customer.hasMany(models.invoice, {
26
+ foreignKey: "customerId",
27
+ as: "invoices",
28
+ });
29
+ };
30
+ customer.selectedFields = [
31
+ "id",
32
+ "name",
33
+ "email",
34
+ "phone",
35
+ "addressLine1",
36
+ "addressLine2",
37
+ "defaultTerms",
38
+ "defaultChartOfAccountId",
39
+ "notes",
40
+ "status",
41
+ "createdAt",
42
+ "updatedAt",
43
+ ];
44
+ return customer;
45
+ };
@@ -0,0 +1,75 @@
1
+ const { INVOICE_STATUS } = require("../../constants");
2
+
3
+ module.exports = (sequelize, DataTypes) => {
4
+ const invoice = sequelize.define(
5
+ "Invoice",
6
+ {
7
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
8
+ invoiceNo: { type: DataTypes.STRING, allowNull: false, unique: true },
9
+ customerId: { type: DataTypes.INTEGER, allowNull: false },
10
+ reference: { type: DataTypes.STRING, allowNull: true },
11
+ description: { type: DataTypes.TEXT, allowNull: true },
12
+ invoiceDate: { type: DataTypes.DATEONLY, allowNull: true },
13
+ dueDate: { type: DataTypes.DATEONLY, allowNull: true },
14
+ terms: { type: DataTypes.STRING, allowNull: true },
15
+ currency: { type: DataTypes.STRING, defaultValue: "USD" },
16
+ memo: { type: DataTypes.TEXT, allowNull: true },
17
+ notes: { type: DataTypes.TEXT, allowNull: true },
18
+ status: { type: DataTypes.STRING, defaultValue: INVOICE_STATUS.DRAFT },
19
+ subtotal: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
20
+ discount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
21
+ amount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
22
+ amountPaid: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
23
+ amountDue: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
24
+ paidDate: { type: DataTypes.DATEONLY, allowNull: true },
25
+ journalEntryId: { type: DataTypes.INTEGER, allowNull: true },
26
+ createdBy: { type: DataTypes.INTEGER, allowNull: true },
27
+ createdAt: { type: DataTypes.DATE },
28
+ updatedAt: { type: DataTypes.DATE },
29
+ },
30
+ { freezeTableName: true, timestamps: false }
31
+ );
32
+ invoice.associate = function (models) {
33
+ invoice.belongsTo(models.customer, {
34
+ foreignKey: "customerId",
35
+ as: "customer",
36
+ });
37
+ invoice.belongsTo(models.journalEntry, {
38
+ foreignKey: "journalEntryId",
39
+ as: "journalEntry",
40
+ });
41
+ invoice.hasMany(models.invoiceLine, {
42
+ foreignKey: "invoiceId",
43
+ as: "invoiceLines",
44
+ });
45
+ invoice.hasMany(models.invoicePayment, {
46
+ foreignKey: "invoiceId",
47
+ as: "invoicePayments",
48
+ });
49
+ };
50
+ invoice.selectedFields = [
51
+ "id",
52
+ "invoiceNo",
53
+ "customerId",
54
+ "reference",
55
+ "description",
56
+ "invoiceDate",
57
+ "dueDate",
58
+ "terms",
59
+ "currency",
60
+ "memo",
61
+ "notes",
62
+ "status",
63
+ "subtotal",
64
+ "discount",
65
+ "amount",
66
+ "amountPaid",
67
+ "amountDue",
68
+ "paidDate",
69
+ "journalEntryId",
70
+ "createdBy",
71
+ "createdAt",
72
+ "updatedAt",
73
+ ];
74
+ return invoice;
75
+ };
@@ -0,0 +1,39 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const invoiceLine = sequelize.define(
3
+ "InvoiceLine",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ invoiceId: { type: DataTypes.INTEGER, allowNull: false },
7
+ chartOfAccountId: { type: DataTypes.INTEGER, allowNull: true },
8
+ description: { type: DataTypes.TEXT, allowNull: true },
9
+ quantity: { type: DataTypes.DECIMAL(12, 2), defaultValue: 1 },
10
+ rate: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
11
+ amount: { type: DataTypes.DECIMAL(12, 2), defaultValue: 0 },
12
+ sortOrder: { type: DataTypes.INTEGER, defaultValue: 0 },
13
+ createdAt: { type: DataTypes.DATE },
14
+ updatedAt: { type: DataTypes.DATE },
15
+ },
16
+ { freezeTableName: true, timestamps: false }
17
+ );
18
+ invoiceLine.associate = function (models) {
19
+ invoiceLine.belongsTo(models.invoice, {
20
+ foreignKey: "invoiceId",
21
+ as: "invoice",
22
+ });
23
+ invoiceLine.belongsTo(models.chartOfAccounts, {
24
+ foreignKey: "chartOfAccountId",
25
+ as: "chartOfAccount",
26
+ });
27
+ };
28
+ invoiceLine.selectedFields = [
29
+ "id",
30
+ "invoiceId",
31
+ "chartOfAccountId",
32
+ "description",
33
+ "quantity",
34
+ "rate",
35
+ "amount",
36
+ "sortOrder",
37
+ ];
38
+ return invoiceLine;
39
+ };
@@ -0,0 +1,48 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const invoicePayment = sequelize.define(
3
+ "InvoicePayment",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ invoiceId: { type: DataTypes.INTEGER, allowNull: false },
7
+ paymentDate: { type: DataTypes.DATEONLY, allowNull: false },
8
+ amount: { type: DataTypes.DECIMAL(12, 2), allowNull: false },
9
+ depositToAccountId: { type: DataTypes.INTEGER, allowNull: false },
10
+ method: { type: DataTypes.STRING, allowNull: true },
11
+ reference: { type: DataTypes.STRING, allowNull: true },
12
+ memo: { type: DataTypes.TEXT, allowNull: true },
13
+ journalEntryId: { type: DataTypes.INTEGER, allowNull: true },
14
+ createdBy: { type: DataTypes.INTEGER, allowNull: true },
15
+ createdAt: { type: DataTypes.DATE },
16
+ updatedAt: { type: DataTypes.DATE },
17
+ },
18
+ { freezeTableName: true, timestamps: false }
19
+ );
20
+ invoicePayment.associate = function (models) {
21
+ invoicePayment.belongsTo(models.invoice, {
22
+ foreignKey: "invoiceId",
23
+ as: "invoice",
24
+ });
25
+ invoicePayment.belongsTo(models.chartOfAccounts, {
26
+ foreignKey: "depositToAccountId",
27
+ as: "depositToAccount",
28
+ });
29
+ invoicePayment.belongsTo(models.journalEntry, {
30
+ foreignKey: "journalEntryId",
31
+ as: "journalEntry",
32
+ });
33
+ };
34
+ invoicePayment.selectedFields = [
35
+ "id",
36
+ "invoiceId",
37
+ "paymentDate",
38
+ "amount",
39
+ "depositToAccountId",
40
+ "method",
41
+ "reference",
42
+ "memo",
43
+ "journalEntryId",
44
+ "createdBy",
45
+ "createdAt",
46
+ ];
47
+ return invoicePayment;
48
+ };
@@ -8,6 +8,10 @@ module.exports = (sequelize, DataTypes) => {
8
8
  debit: { type: DataTypes.DECIMAL(10, 2), defaultValue: 0 },
9
9
  credit: { type: DataTypes.DECIMAL(10, 2), defaultValue: 0 },
10
10
  memo: { type: DataTypes.TEXT, allowNull: true },
11
+ // Bank reconciliation: cleared is toggled while a reconciliation is in progress;
12
+ // bankReconciliationId is stamped once that reconciliation is completed, locking the line in.
13
+ cleared: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
14
+ bankReconciliationId: { type: DataTypes.INTEGER, allowNull: true },
11
15
  createdAt: { type: DataTypes.DATE },
12
16
  updatedAt: { type: DataTypes.DATE },
13
17
  },
@@ -22,6 +26,10 @@ module.exports = (sequelize, DataTypes) => {
22
26
  foreignKey: "chartOfAccountId",
23
27
  as: "chartOfAccount",
24
28
  });
29
+ journalEntryLine.belongsTo(models.bankReconciliation, {
30
+ foreignKey: "bankReconciliationId",
31
+ as: "bankReconciliation",
32
+ });
25
33
  };
26
34
  journalEntryLine.selectedFields = [
27
35
  "id",
@@ -30,6 +38,8 @@ module.exports = (sequelize, DataTypes) => {
30
38
  "debit",
31
39
  "credit",
32
40
  "memo",
41
+ "cleared",
42
+ "bankReconciliationId",
33
43
  "createdAt",
34
44
  "updatedAt",
35
45
  ];
@@ -0,0 +1,45 @@
1
+ module.exports = (sequelize, DataTypes) => {
2
+ const vendor = sequelize.define(
3
+ "Vendor",
4
+ {
5
+ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
6
+ name: { type: DataTypes.STRING, allowNull: false, unique: true },
7
+ email: { type: DataTypes.STRING, allowNull: true },
8
+ phone: { type: DataTypes.STRING, allowNull: true },
9
+ addressLine1: { type: DataTypes.STRING, allowNull: true },
10
+ addressLine2: { type: DataTypes.STRING, allowNull: true },
11
+ defaultTerms: { type: DataTypes.STRING, allowNull: true },
12
+ defaultChartOfAccountId: { type: DataTypes.INTEGER, allowNull: true },
13
+ notes: { type: DataTypes.TEXT, allowNull: true },
14
+ status: { type: DataTypes.BOOLEAN, defaultValue: true },
15
+ createdAt: { type: DataTypes.DATE },
16
+ updatedAt: { type: DataTypes.DATE },
17
+ },
18
+ { freezeTableName: true, timestamps: false }
19
+ );
20
+ vendor.associate = function (models) {
21
+ vendor.belongsTo(models.chartOfAccounts, {
22
+ foreignKey: "defaultChartOfAccountId",
23
+ as: "defaultChartOfAccount",
24
+ });
25
+ vendor.hasMany(models.bill, {
26
+ foreignKey: "vendorId",
27
+ as: "bills",
28
+ });
29
+ };
30
+ vendor.selectedFields = [
31
+ "id",
32
+ "name",
33
+ "email",
34
+ "phone",
35
+ "addressLine1",
36
+ "addressLine2",
37
+ "defaultTerms",
38
+ "defaultChartOfAccountId",
39
+ "notes",
40
+ "status",
41
+ "createdAt",
42
+ "updatedAt",
43
+ ];
44
+ return vendor;
45
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@churchsoln/dbms",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "prestart": "node db-setup.js",
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ const { ACCOUNTS_PAYABLE_CODE, CHART_OF_ACCOUNTS } = require("../../constants");
4
+
5
+ // The chartOfAccounts seeder is tracked in SequelizeData, so existing churches never re-run it.
6
+ // This seeder adds the Accounts Payable account that bills post to.
7
+ module.exports = {
8
+ up: async (queryInterface) => {
9
+ const account = CHART_OF_ACCOUNTS.find((a) => a.code === ACCOUNTS_PAYABLE_CODE);
10
+ const existingId = await queryInterface.rawSelect(
11
+ "ChartOfAccounts",
12
+ { where: { code: account.code } },
13
+ ["id"]
14
+ );
15
+ if (existingId) return;
16
+
17
+ const accountingAccountTypeId = await queryInterface.rawSelect(
18
+ "AccountingAccountTypes",
19
+ { where: { name: account.accountingAccountType } },
20
+ ["id"]
21
+ );
22
+ // Account types are seeded by 20260706170638-accountingAccountTypes; without them there is no chart to extend.
23
+ if (!accountingAccountTypeId) return;
24
+ const parentAccountId = await queryInterface.rawSelect(
25
+ "ChartOfAccounts",
26
+ { where: { code: account.parentCode } },
27
+ ["id"]
28
+ );
29
+ await queryInterface.bulkInsert("ChartOfAccounts", [
30
+ {
31
+ code: account.code,
32
+ name: account.name,
33
+ accountingAccountTypeId,
34
+ parentAccountId: parentAccountId || null,
35
+ isPostingAccount: account.isPostingAccount,
36
+ status: true,
37
+ },
38
+ ]);
39
+ },
40
+
41
+ down: async (queryInterface) => {
42
+ await queryInterface.bulkDelete("ChartOfAccounts", { code: ACCOUNTS_PAYABLE_CODE });
43
+ },
44
+ };