@social-mail/social-mail-web-server 1.5.330 → 1.5.331
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.
- package/dist/server/model/entities/StoreJournal.d.ts +3 -1
- package/dist/server/model/entities/StoreJournal.d.ts.map +1 -1
- package/dist/server/model/entities/StoreJournal.js +7 -1
- package/dist/server/model/entities/StoreJournal.js.map +1 -1
- package/dist/server/model/events/StoreJournalCouponEvents.d.ts +5 -0
- package/dist/server/model/events/StoreJournalCouponEvents.d.ts.map +1 -1
- package/dist/server/model/events/StoreJournalCouponEvents.js +32 -1
- package/dist/server/model/events/StoreJournalCouponEvents.js.map +1 -1
- package/dist/server/model/events/StoreJournalEvents.d.ts.map +1 -1
- package/dist/server/model/events/StoreJournalEvents.js +0 -1
- package/dist/server/model/events/StoreJournalEvents.js.map +1 -1
- package/dist/server/seed/ui/seed-ui.js +1 -1
- package/dist/server/services/accounts/sales/SalesInvoiceService.d.ts.map +1 -1
- package/dist/server/services/accounts/sales/SalesInvoiceService.js +14 -6
- package/dist/server/services/accounts/sales/SalesInvoiceService.js.map +1 -1
- package/dist/server/services/coupons/CouponService.d.ts.map +1 -1
- package/dist/server/services/coupons/CouponService.js +8 -1
- package/dist/server/services/coupons/CouponService.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/wwwroot/routes/store/buy/[productID]/get.d.ts.map +1 -1
- package/dist/wwwroot/routes/store/buy/[productID]/get.js +2 -1
- package/dist/wwwroot/routes/store/buy/[productID]/get.js.map +1 -1
- package/package.json +1 -1
- package/src/server/model/entities/StoreJournal.ts +10 -2
- package/src/server/model/events/StoreJournalCouponEvents.ts +45 -1
- package/src/server/model/events/StoreJournalEvents.ts +0 -2
- package/src/server/seed/ui/seed-ui.ts +1 -1
- package/src/server/services/accounts/sales/SalesInvoiceService.ts +16 -6
- package/src/server/services/coupons/CouponService.ts +9 -1
- package/src/wwwroot/routes/store/buy/[productID]/get.tsx +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../../../src/wwwroot/routes/store/buy/[productID]/get.tsx"],"names":[],"mappings":"AAGA,OAAO,IAAI,MAAM,0CAA0C,CAAC;AAE5D,OAAO,iBAAiB,MAAM,kDAAkD,CAAC;AACjF,OAAO,cAAc,MAAM,wDAAwD,CAAC;AACpF,OAAO,kBAAkB,MAAM,4DAA4D,CAAC;
|
|
1
|
+
{"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../../../src/wwwroot/routes/store/buy/[productID]/get.tsx"],"names":[],"mappings":"AAGA,OAAO,IAAI,MAAM,0CAA0C,CAAC;AAE5D,OAAO,iBAAiB,MAAM,kDAAkD,CAAC;AACjF,OAAO,cAAc,MAAM,wDAAwD,CAAC;AACpF,OAAO,kBAAkB,MAAM,4DAA4D,CAAC;AAK5F,MAAM,CAAC,OAAO,MAAO,SAAQ,IAAI;IAG7B,SAAS,MAAC;IAGV,EAAE,EAAE,iBAAiB,CAAC;IAGtB,kBAAkB,EAAE,kBAAkB,CAAC;IAGvC,cAAc,EAAE,cAAc,CAAC;IAEzB,GAAG;CA4DZ"}
|
|
@@ -14,6 +14,7 @@ import { Prepare } from "@entity-access/server-pages/dist/decorators/Prepare.js"
|
|
|
14
14
|
import SocialMailContext from "../../../../../server/model/SocialMailContext.js";
|
|
15
15
|
import WebSiteService from "../../../../../server/services/files/WebSiteService.js";
|
|
16
16
|
import StoreConfigService from "../../../../../server/services/store/StoreConfigService.js";
|
|
17
|
+
import EntityAccessError from "@entity-access/entity-access/dist/common/EntityAccessError.js";
|
|
17
18
|
let default_1 = class extends Page {
|
|
18
19
|
async run() {
|
|
19
20
|
// only if logged in...
|
|
@@ -29,7 +30,7 @@ let default_1 = class extends Page {
|
|
|
29
30
|
}
|
|
30
31
|
const contact = await this.db.storeAccounts.where({ userID }, (p) => (x) => x.accountID === p.userID)
|
|
31
32
|
.include((x) => x.addresses)
|
|
32
|
-
.first();
|
|
33
|
+
.first() ?? EntityAccessError.throw(`Please signup as a store user instead of backend user.`);
|
|
33
34
|
// todo: optimization
|
|
34
35
|
// do not create new orders if new order for same item exists
|
|
35
36
|
// with only a single item...
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../../../src/wwwroot/routes/store/buy/[productID]/get.tsx"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,MAAM,MAAM,4CAA4C,CAAC;AAEhE,OAAO,EAAE,KAAK,EAAE,MAAM,gDAAgD,CAAC;AACvE,OAAO,IAAI,MAAM,0CAA0C,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,wDAAwD,CAAC;AACjF,OAAO,iBAAiB,MAAM,kDAAkD,CAAC;AACjF,OAAO,cAAc,MAAM,wDAAwD,CAAC;AACpF,OAAO,kBAAkB,MAAM,4DAA4D,CAAC;
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../../../src/wwwroot/routes/store/buy/[productID]/get.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -16,6 +16,9 @@ const journalTypeArray = [ "order", "purchase-order", "sales-invoice", "journal"
|
|
|
16
16
|
export type journalTypeArrayType = typeof journalTypeArray[number];
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
const statusTypeArray = [ "new", "paid", "draft"] as const;
|
|
20
|
+
export type statusType = typeof statusTypeArray[number];
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
@Table("StoreJournals")
|
|
21
24
|
export class StoreJournal {
|
|
@@ -45,8 +48,13 @@ export class StoreJournal {
|
|
|
45
48
|
@Column({ dataType: "Boolean", default: () => false })
|
|
46
49
|
posted: boolean;
|
|
47
50
|
|
|
48
|
-
@Column({
|
|
49
|
-
|
|
51
|
+
@Column({
|
|
52
|
+
dataType: "Char",
|
|
53
|
+
length: 50,
|
|
54
|
+
default: () => "draft",
|
|
55
|
+
enum: statusTypeArray
|
|
56
|
+
})
|
|
57
|
+
status: statusType;
|
|
50
58
|
|
|
51
59
|
@Column({ dataType: "BigInt" ,nullable: true })
|
|
52
60
|
@RelateTo(StoreAccount, {
|
|
@@ -6,12 +6,18 @@ import ChangeEntry from "@entity-access/entity-access/dist/model/changes/ChangeE
|
|
|
6
6
|
import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
|
|
7
7
|
import Inject from "@entity-access/entity-access/dist/di/di.js";
|
|
8
8
|
import CouponService from "../../services/coupons/CouponService.js";
|
|
9
|
+
import SocialMailContext from "../SocialMailContext.js";
|
|
10
|
+
import { ForeignKeyFilter } from "@entity-access/entity-access/dist/model/events/EntityEvents.js";
|
|
11
|
+
import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
|
|
9
12
|
|
|
10
13
|
export default class StoreJournalCouponEvents extends AuthenticatedEvents<StoreJournalCoupon> {
|
|
11
14
|
|
|
12
15
|
@Inject
|
|
13
16
|
couponService: CouponService;
|
|
14
17
|
|
|
18
|
+
@Inject
|
|
19
|
+
db: SocialMailContext;
|
|
20
|
+
|
|
15
21
|
filter(query: IEntityQuery<StoreJournalCoupon>) {
|
|
16
22
|
if (!this.verify) {
|
|
17
23
|
return query;
|
|
@@ -38,7 +44,7 @@ export default class StoreJournalCouponEvents extends AuthenticatedEvents<StoreJ
|
|
|
38
44
|
if (sessionUser.isAdmin) {
|
|
39
45
|
return query;
|
|
40
46
|
}
|
|
41
|
-
|
|
47
|
+
return this.modify(query);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
includeFilter(query: IEntityQuery<StoreJournalCoupon>, type?: any, key?: string) {
|
|
@@ -47,11 +53,49 @@ export default class StoreJournalCouponEvents extends AuthenticatedEvents<StoreJ
|
|
|
47
53
|
|
|
48
54
|
async beforeInsert(entity: StoreJournalCoupon, entry: ChangeEntry<StoreJournalCoupon>) {
|
|
49
55
|
this.sessionUser.ensureLoggedIn();
|
|
56
|
+
|
|
57
|
+
if (!entity.couponID) {
|
|
58
|
+
await entry.loadNavigationAsync((x) => x.order);
|
|
59
|
+
|
|
60
|
+
const { storeID } = entity.order;
|
|
61
|
+
const { couponCode } = entity;
|
|
62
|
+
|
|
63
|
+
const ce = this.db.changeSet.getEntry(entity.order);
|
|
64
|
+
entity.order.dateUpdated = DateTime.now;
|
|
65
|
+
ce.detect();
|
|
66
|
+
|
|
67
|
+
const coupon = await this.db.storeCoupons.where({ storeID, couponCode }, (p) => (x) => x.storeID === p.storeID
|
|
68
|
+
&& x.code === p.couponCode
|
|
69
|
+
)
|
|
70
|
+
.first() ?? EntityAccessError.throw(`Coupon ${entity.couponCode} not found`);
|
|
71
|
+
|
|
72
|
+
entity.couponID = coupon.couponID;
|
|
73
|
+
entity.coupon = coupon;
|
|
74
|
+
}
|
|
75
|
+
|
|
50
76
|
await this.couponService.apply(entity, entry);
|
|
51
77
|
}
|
|
52
78
|
|
|
79
|
+
async beforeDelete(entity: StoreJournalCoupon, entry: ChangeEntry<StoreJournalCoupon>) {
|
|
80
|
+
this.sessionUser.ensureLoggedIn();
|
|
81
|
+
|
|
82
|
+
const isNonPaid = await this.db.storeJournalCoupons.where(entity, (p) => (x) =>
|
|
83
|
+
x.appliedCouponID === p.appliedCouponID
|
|
84
|
+
&& x.order.status !== "paid"
|
|
85
|
+
)
|
|
86
|
+
.first();
|
|
87
|
+
|
|
88
|
+
if (!isNonPaid) {
|
|
89
|
+
throw new EntityAccessError(`Coupon cannot be deleted from paid order`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
53
93
|
beforeUpdate(entity: StoreJournalCoupon, entry: ChangeEntry<StoreJournalCoupon>) {
|
|
54
94
|
throw new EntityAccessError(`Cannot modify coupon, delete and add it again.`);
|
|
55
95
|
}
|
|
56
96
|
|
|
97
|
+
onForeignKeyFilter(filter: ForeignKeyFilter<StoreJournalCoupon, any>) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
57
101
|
}
|
|
@@ -79,8 +79,6 @@ export default class StoreJournalEvents extends AuthenticatedEvents<StoreJournal
|
|
|
79
79
|
if(entry.getChange("posted").oldValue) {
|
|
80
80
|
throw new EntityAccessError("Posted journal cannot be saved as draft.");
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
await this.syncAmount(entry);
|
|
84
82
|
await this.verifyEntries(entry);
|
|
85
83
|
|
|
86
84
|
} else {
|
|
@@ -22,7 +22,7 @@ export default class SalesInvoiceService {
|
|
|
22
22
|
async syncAmount(entry: ChangeEntry<StoreJournal>, entity: StoreJournal) {
|
|
23
23
|
|
|
24
24
|
await this.db.storeJournals.where(entity, (p) => (x) => x.journalID === p.journalID)
|
|
25
|
-
.include((x) => [x.lineItems.forEach((i) => [i.coupons, i.itemPrice])])
|
|
25
|
+
.include((x) => [x.lineItems.forEach((i) => [i.coupons.forEach((c) => c.coupon), i.itemPrice])])
|
|
26
26
|
.first();
|
|
27
27
|
|
|
28
28
|
for(const lineItem of [...entity.lineItems]) {
|
|
@@ -37,11 +37,15 @@ export default class SalesInvoiceService {
|
|
|
37
37
|
const itemAmount = Number(lineItem.price) * Number(lineItem.quantity);
|
|
38
38
|
|
|
39
39
|
if (lineItem.discountPercentage) {
|
|
40
|
-
lineItem.discount = lineItem.discountPercentage * lineItem.amount;
|
|
40
|
+
lineItem.discount = Number(lineItem.discountPercentage) * Number(lineItem.amount);
|
|
41
|
+
} else {
|
|
42
|
+
lineItem.discount = 0;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
const priceAfterDiscount = itemAmount - lineItem.discount;
|
|
44
46
|
|
|
47
|
+
lineItem.couponDiscount ??= 0;
|
|
48
|
+
|
|
45
49
|
if (priceAfterDiscount !== Number(lineItem.priceAfterDiscount)) {
|
|
46
50
|
lineItem.priceAfterDiscount = priceAfterDiscount;
|
|
47
51
|
await this.db.storeJournalLineItems.statements.update(
|
|
@@ -74,7 +78,13 @@ export default class SalesInvoiceService {
|
|
|
74
78
|
|
|
75
79
|
let taxes = 0;
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
await this.coupons.compute(lineItem);
|
|
82
|
+
|
|
83
|
+
lineItem.couponDiscount = Number(lineItem.couponDiscount);
|
|
84
|
+
lineItem.quantity ??= 0;
|
|
85
|
+
lineItem.quantity = Number(lineItem.quantity);
|
|
86
|
+
|
|
87
|
+
lineItem.amount = (lineItem.priceAfterDiscount - Number(lineItem.couponDiscount)) * lineItem.quantity;
|
|
78
88
|
|
|
79
89
|
for(const price of itemPrices) {
|
|
80
90
|
let taxLine = lineItem.taxLineItems.find((r) =>
|
|
@@ -95,14 +105,14 @@ export default class SalesInvoiceService {
|
|
|
95
105
|
|
|
96
106
|
if(itemPrice.taxIncluded) {
|
|
97
107
|
|
|
98
|
-
let amount = lineItem.amount
|
|
108
|
+
let amount = lineItem.amount;
|
|
99
109
|
amount = amount / (Number(price.amount) + 1);
|
|
100
|
-
lineItem.amount = amount
|
|
110
|
+
lineItem.amount = amount;
|
|
101
111
|
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
taxLine.price = Number(price.amount);
|
|
105
|
-
taxLine.total =
|
|
115
|
+
taxLine.total = Number(lineItem.amount) * Number(price.amount);
|
|
106
116
|
taxes += taxLine.total;
|
|
107
117
|
}
|
|
108
118
|
lineItem.taxes = taxes;
|
|
@@ -39,6 +39,11 @@ export default class CouponService {
|
|
|
39
39
|
|
|
40
40
|
let applicableItems = order.lineItems;
|
|
41
41
|
|
|
42
|
+
if (!orderCoupon.couponID) {
|
|
43
|
+
orderCoupon.couponID = coupon.couponID;
|
|
44
|
+
orderCoupon.coupon = coupon;
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
if (coupon.itemID) {
|
|
43
48
|
applicableItems = order.lineItems.filter((i) => i.itemID === coupon.itemID);
|
|
44
49
|
if (!applicableItems.length) {
|
|
@@ -81,13 +86,16 @@ export default class CouponService {
|
|
|
81
86
|
// set couponDiscount amount
|
|
82
87
|
|
|
83
88
|
const coupons = lineItem.coupons ?? lineItem.journal.orderCoupons;
|
|
84
|
-
if (!coupons) {
|
|
89
|
+
if (!coupons?.length) {
|
|
85
90
|
return;
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
lineItem.couponDiscount = 0;
|
|
89
94
|
|
|
90
95
|
for (const coupon of coupons) {
|
|
96
|
+
if (!coupon.coupon) {
|
|
97
|
+
await this.db.changeSet.getEntry(coupon).loadNavigationAsync((x) => x.coupon);
|
|
98
|
+
}
|
|
91
99
|
switch(coupon.coupon.type) {
|
|
92
100
|
case "discount":
|
|
93
101
|
lineItem.couponDiscount += lineItem.priceAfterDiscount * Number(coupon.coupon.amount);
|
|
@@ -6,6 +6,7 @@ import { Prepare } from "@entity-access/server-pages/dist/decorators/Prepare.js"
|
|
|
6
6
|
import SocialMailContext from "../../../../../server/model/SocialMailContext.js";
|
|
7
7
|
import WebSiteService from "../../../../../server/services/files/WebSiteService.js";
|
|
8
8
|
import StoreConfigService from "../../../../../server/services/store/StoreConfigService.js";
|
|
9
|
+
import EntityAccessError from "@entity-access/entity-access/dist/common/EntityAccessError.js";
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@Prepare.authorize
|
|
@@ -44,7 +45,7 @@ export default class extends Page {
|
|
|
44
45
|
|
|
45
46
|
const contact = await this.db.storeAccounts.where({userID }, (p) => (x) => x.accountID === p.userID)
|
|
46
47
|
.include((x) => x.addresses)
|
|
47
|
-
.first();
|
|
48
|
+
.first() ?? EntityAccessError.throw(`Please signup as a store user instead of backend user.`);
|
|
48
49
|
|
|
49
50
|
// todo: optimization
|
|
50
51
|
// do not create new orders if new order for same item exists
|