@storecraft/sdk 0.1.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.
- package/README.md +132 -0
- package/index.js +103 -0
- package/package.json +29 -0
- package/src/auth.js +382 -0
- package/src/bots.js +113 -0
- package/src/collections.js +129 -0
- package/src/customers.js +21 -0
- package/src/discounts.js +149 -0
- package/src/images.js +21 -0
- package/src/notifications.js +102 -0
- package/src/orders.js +47 -0
- package/src/payments.js +89 -0
- package/src/posts.js +22 -0
- package/src/products.js +74 -0
- package/src/settings.js +19 -0
- package/src/shipping.js +22 -0
- package/src/statistics.js +99 -0
- package/src/storage.js +325 -0
- package/src/storefronts.js +113 -0
- package/src/tags.js +21 -0
- package/src/templates.js +21 -0
- package/src/utils.api.fetch.js +281 -0
- package/src/utils.functional.js +141 -0
- package/tsconfig.json +29 -0
- package/types.d.ts +1 -0
package/src/bots.js
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
|
3
|
+
export const SECOND = 1000
|
4
|
+
export const MINUTE = SECOND*60
|
5
|
+
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @typedef {object} BotMetaData
|
9
|
+
* @property {number} updatedAt
|
10
|
+
*
|
11
|
+
*/
|
12
|
+
|
13
|
+
const NAME = 'bots'
|
14
|
+
|
15
|
+
export default class Bots {
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @param {StorecraftSDK} context
|
19
|
+
*/
|
20
|
+
constructor(context) {
|
21
|
+
this.context = context
|
22
|
+
this.db = context.db
|
23
|
+
}
|
24
|
+
|
25
|
+
init = async () => {
|
26
|
+
// this.activitySpy()
|
27
|
+
this.activityBot()
|
28
|
+
setInterval(
|
29
|
+
this.activityBot,
|
30
|
+
MINUTE*10
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
activityBot = async () => {
|
35
|
+
// console.trace()
|
36
|
+
try {
|
37
|
+
const db = this.db.firebaseDB
|
38
|
+
const result = await runTransaction(
|
39
|
+
this.db.firebaseDB,
|
40
|
+
async t => {
|
41
|
+
const now = Date.now()
|
42
|
+
const ref = doc(db, NAME, 'shelf-activity-bot')
|
43
|
+
const m = await t.get(ref)
|
44
|
+
const updatedAt = m.data()?.updatedAt ?? 0
|
45
|
+
|
46
|
+
const q = {
|
47
|
+
where: [
|
48
|
+
['updatedAt', '>', updatedAt]
|
49
|
+
]
|
50
|
+
}
|
51
|
+
|
52
|
+
const cols = ['collections', 'products', 'users', 'tags', 'discounts']
|
53
|
+
const results = cols.map(
|
54
|
+
async c => [c, await this.db.col(c).count(q)]
|
55
|
+
)
|
56
|
+
|
57
|
+
t.set(
|
58
|
+
m.ref,
|
59
|
+
{
|
60
|
+
updatedAt: now
|
61
|
+
}
|
62
|
+
)
|
63
|
+
|
64
|
+
return await Promise.all(results)
|
65
|
+
|
66
|
+
},
|
67
|
+
{
|
68
|
+
maxAttempts: 1
|
69
|
+
}
|
70
|
+
)
|
71
|
+
|
72
|
+
let filtered = result.filter(
|
73
|
+
it => it[1]
|
74
|
+
)
|
75
|
+
|
76
|
+
if(filtered.length==0)
|
77
|
+
return
|
78
|
+
|
79
|
+
const search = filtered.map(it => it[0])
|
80
|
+
const messages = filtered.map(
|
81
|
+
it => {
|
82
|
+
const [c, count] = it
|
83
|
+
return `\n* 🚀 **${count}** \`${c}\` were updated`
|
84
|
+
}
|
85
|
+
);
|
86
|
+
|
87
|
+
const message = ["**Latest Activity updates**", ...messages].join(' ')
|
88
|
+
/**@type {NotificationData} */
|
89
|
+
const noti = {
|
90
|
+
message,
|
91
|
+
search,
|
92
|
+
author: 'shelf-activity-bot 🤖',
|
93
|
+
updatedAt: Date.now()
|
94
|
+
}
|
95
|
+
|
96
|
+
// console.log(messages)
|
97
|
+
// console.log(message)
|
98
|
+
|
99
|
+
await this.context.notifications.add(
|
100
|
+
noti
|
101
|
+
)
|
102
|
+
|
103
|
+
} catch (e) {
|
104
|
+
// failed because another the document updated from another client
|
105
|
+
// this is ok
|
106
|
+
console.log(e)
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
}
|
112
|
+
|
113
|
+
}
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import { collection_base } from './utils.api.fetch.js';
|
3
|
+
import { filter_fields, filter_unused } from './utils.functional.js';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Base `collections` **CRUD**
|
7
|
+
*
|
8
|
+
* @extends {collection_base<
|
9
|
+
* import('@storecraft/core/v-api').CollectionTypeUpsert,
|
10
|
+
* import('@storecraft/core/v-api').CollectionType>
|
11
|
+
* }
|
12
|
+
*/
|
13
|
+
export default class Collections extends collection_base {
|
14
|
+
|
15
|
+
/**
|
16
|
+
*
|
17
|
+
* @param {StorecraftSDK} sdk
|
18
|
+
*/
|
19
|
+
constructor(sdk) {
|
20
|
+
super(sdk, 'collections');
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
*
|
25
|
+
* @param {string} collection_handle
|
26
|
+
* @param {number} limit
|
27
|
+
*/
|
28
|
+
publish = async (collection_handle, limit=1000) => {
|
29
|
+
throw new Error('Implement me !!!')
|
30
|
+
// extra filtering for validation
|
31
|
+
|
32
|
+
try {
|
33
|
+
// fetch collection
|
34
|
+
var [exists, id, collection] = await this.get(collection_handle)
|
35
|
+
} catch (e) {
|
36
|
+
throw 'Collection read error: ' + String(e)
|
37
|
+
}
|
38
|
+
|
39
|
+
// get all products in collection
|
40
|
+
try {
|
41
|
+
var pick_data = items => items.map(item => item[1])
|
42
|
+
/** @param {ProductData[]} items */
|
43
|
+
var filter_hard_on_collection = items => items.filter(
|
44
|
+
item => (
|
45
|
+
item.collections &&
|
46
|
+
item.collections.indexOf(collection_handle)>=0 &&
|
47
|
+
item.qty>0 &&
|
48
|
+
(item.active || item.active===undefined) &&
|
49
|
+
(!item.parent_handle)
|
50
|
+
)
|
51
|
+
)
|
52
|
+
const filter_fields_in = filter_fields(
|
53
|
+
'title', 'handle', 'media', 'desc', 'price', 'attributes',
|
54
|
+
'video', 'tags', 'updatedAt', 'compareAtPrice', 'discounts',
|
55
|
+
'parent_handle', 'variants_options', 'variants_products'
|
56
|
+
)
|
57
|
+
var products = await this.context.products.list(
|
58
|
+
[`col:${collection_handle}`], limit
|
59
|
+
)
|
60
|
+
// console.log('products', products)
|
61
|
+
products = pick_data(products)
|
62
|
+
products = filter_hard_on_collection(products)
|
63
|
+
products = filter_fields_in(products)
|
64
|
+
products = filter_unused(products)
|
65
|
+
} catch (e) {
|
66
|
+
throw 'products read error: ' + String(e)
|
67
|
+
}
|
68
|
+
|
69
|
+
try {
|
70
|
+
// upload collection export
|
71
|
+
const metadata = {
|
72
|
+
contentType: 'application/json',
|
73
|
+
contentEncoding: 'gzip',
|
74
|
+
cacheControl: `max-age=${60*60*1}, must-revalidate`
|
75
|
+
// cacheControl: `private, max-age=${60*60*1}`
|
76
|
+
// cacheControl: `max-age=${60*60*5}, must-revalidate`
|
77
|
+
}
|
78
|
+
var [url, ref] = await this.context.storage.uploadBytes(
|
79
|
+
`collections/${collection_handle}.json`,
|
80
|
+
pako.gzip(
|
81
|
+
JSON.stringify({
|
82
|
+
...collection,
|
83
|
+
products
|
84
|
+
})
|
85
|
+
),
|
86
|
+
metadata
|
87
|
+
)
|
88
|
+
} catch(e) {
|
89
|
+
throw 'Collection upload error: ' + String(e)
|
90
|
+
}
|
91
|
+
|
92
|
+
try {
|
93
|
+
await this.update(collection_handle, { _published: url })
|
94
|
+
} catch (e) {
|
95
|
+
throw 'Collection update error: ' + String(e)
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// /**
|
100
|
+
// * Add tags in bulk to products in collection
|
101
|
+
// * @param {string} colId
|
102
|
+
// * @param {string[]} tags
|
103
|
+
// * @param {boolean} add true for add false for remove
|
104
|
+
// */
|
105
|
+
// bulkAddRemoveTags = async (colId, tags, add=true) => {
|
106
|
+
|
107
|
+
// // first get all products in collection
|
108
|
+
// const tag_all = tags ?? []
|
109
|
+
// const tag_all_prefixed = tag_all.map(t => `tag:${t}`)
|
110
|
+
// const tag_vs = tag_all.map(it => it.split('_').pop())
|
111
|
+
|
112
|
+
// var products = await this.context.products.list([`col:${colId}`], 10000)
|
113
|
+
// // console.log('products ', products)
|
114
|
+
// // console.log('colId ', colId)
|
115
|
+
// const batch = writeBatch(this.context.firebase.db)
|
116
|
+
// products.forEach(it => {
|
117
|
+
// const ref = doc(this.context.firebase.db, 'products', it[0])
|
118
|
+
// batch.update(ref, {
|
119
|
+
// tags : add ? arrayUnion(...tags) : arrayRemove(...tags),
|
120
|
+
// search : add ? arrayUnion(...tag_all, ...tag_all_prefixed, ...tag_vs) :
|
121
|
+
// arrayRemove(...tag_all, ...tag_all_prefixed, ...tag_vs),
|
122
|
+
// updatedAt : Date.now()
|
123
|
+
// })
|
124
|
+
// })
|
125
|
+
// await batch.commit()
|
126
|
+
|
127
|
+
// }
|
128
|
+
|
129
|
+
}
|
package/src/customers.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import { collection_base } from './utils.api.fetch.js';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Base `customers` **CRUD**
|
6
|
+
*
|
7
|
+
* @extends {collection_base<
|
8
|
+
* import('@storecraft/core/v-api').CustomerTypeUpsert,
|
9
|
+
* import('@storecraft/core/v-api').CustomerType>
|
10
|
+
* }
|
11
|
+
*/
|
12
|
+
export default class Customers extends collection_base {
|
13
|
+
|
14
|
+
/**
|
15
|
+
*
|
16
|
+
* @param {StorecraftSDK} sdk
|
17
|
+
*/
|
18
|
+
constructor(sdk) {
|
19
|
+
super(sdk, 'customers');
|
20
|
+
}
|
21
|
+
}
|
package/src/discounts.js
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import { collection_base } from './utils.api.fetch.js';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Base `discounts` **CRUD**
|
6
|
+
*
|
7
|
+
* @extends {collection_base<
|
8
|
+
* import('@storecraft/core/v-api').DiscountTypeUpsert,
|
9
|
+
* import('@storecraft/core/v-api').DiscountType>
|
10
|
+
* }
|
11
|
+
*/
|
12
|
+
export default class Discounts extends collection_base {
|
13
|
+
|
14
|
+
/**
|
15
|
+
*
|
16
|
+
* @param {StorecraftSDK} sdk
|
17
|
+
*/
|
18
|
+
constructor(sdk) {
|
19
|
+
super(sdk, 'discounts');
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
*
|
24
|
+
* @param {DiscountData} discount_data
|
25
|
+
* @param {number} limit
|
26
|
+
*/
|
27
|
+
publish = async (discount_data, limit=10000) => {
|
28
|
+
const coll_handle = `discount-${discount_data.code}`
|
29
|
+
const dd = {
|
30
|
+
...discount_data,
|
31
|
+
_published: coll_handle
|
32
|
+
}
|
33
|
+
if(dd.info.details.meta.type==='order')
|
34
|
+
throw 'Exporting a discount collection is only available for \
|
35
|
+
Product discounts (you chose Order discount)'
|
36
|
+
|
37
|
+
// save current document, allow to fail
|
38
|
+
await this.set(
|
39
|
+
dd.code, dd
|
40
|
+
)
|
41
|
+
// await this.update(dd.code, { _published: coll_handle })
|
42
|
+
|
43
|
+
|
44
|
+
// first, remove all previous collection tag from previous products
|
45
|
+
try {
|
46
|
+
const products_to_remove =
|
47
|
+
await this.context.products.list([`col:${coll_handle}`], 10000)
|
48
|
+
// console.log('products_to_remove ', products_to_remove);
|
49
|
+
const batch_remove = writeBatch(this.context.firebase.db)
|
50
|
+
products_to_remove.forEach(it => {
|
51
|
+
const ref = doc(this.context.firebase.db, 'products', it[0])
|
52
|
+
batch_remove.update(ref, {
|
53
|
+
search : arrayRemove(`col:${coll_handle}`),
|
54
|
+
collections : arrayRemove(coll_handle),
|
55
|
+
[`discounts.${dd.code}`]: deleteField()
|
56
|
+
})
|
57
|
+
})
|
58
|
+
await batch_remove.commit()
|
59
|
+
|
60
|
+
} catch (e) {
|
61
|
+
console.log('Remove old: ' + String(e))
|
62
|
+
console.log(e)
|
63
|
+
}
|
64
|
+
|
65
|
+
try {
|
66
|
+
// filter in product filters
|
67
|
+
var product_filters = dd.info.filters.filter(f => f.meta.type==='product')
|
68
|
+
|
69
|
+
// then, make a server search that will filter out as much as possible
|
70
|
+
/**@type {Filter} */
|
71
|
+
var first_guided_filter = undefined
|
72
|
+
/**@type {string[]} */
|
73
|
+
var first_guided_search_terms = undefined
|
74
|
+
|
75
|
+
if(first_guided_filter = product_filters.find(f => f.meta.op==='p-in-handles')) {
|
76
|
+
first_guided_search_terms = first_guided_filter.value
|
77
|
+
}
|
78
|
+
else if(first_guided_filter = product_filters.find(f => f.meta.op==='p-in-tags')) {
|
79
|
+
first_guided_search_terms = first_guided_filter.value.map(t => `tag:${t}`)
|
80
|
+
}
|
81
|
+
else if(first_guided_filter = product_filters.find(f => f.meta.op==='p-in-collections')) {
|
82
|
+
first_guided_search_terms = first_guided_filter.value.map(c => `col:${c}`)
|
83
|
+
}
|
84
|
+
} catch (e) {
|
85
|
+
throw 'Filter preparing error: ' + String(e)
|
86
|
+
}
|
87
|
+
|
88
|
+
try {
|
89
|
+
// then, global filtering, this helps to reduce legal products for filtering
|
90
|
+
var products = await
|
91
|
+
this.context.products.list(first_guided_search_terms, limit)
|
92
|
+
|
93
|
+
// now local filtering (due to firebase limitations with filtering)
|
94
|
+
var filtered_products =
|
95
|
+
this.filterProductsWithFilters(products, product_filters)
|
96
|
+
|
97
|
+
// products = products.slice(0, 400)
|
98
|
+
} catch (e) {
|
99
|
+
throw 'Filtering error: ' + String(e)
|
100
|
+
}
|
101
|
+
|
102
|
+
try {
|
103
|
+
// add collection tag to each product with batch write
|
104
|
+
const batch = writeBatch(this.context.firebase.db)
|
105
|
+
filtered_products.forEach(it => {
|
106
|
+
const p = it[1]
|
107
|
+
const isActive = p?.active==true || (p.active===undefined)
|
108
|
+
if(!isActive)
|
109
|
+
return;
|
110
|
+
|
111
|
+
const ref = doc(this.context.firebase.db, 'products', it[0])
|
112
|
+
const dd_mod = {...dd}
|
113
|
+
delete dd_mod.search
|
114
|
+
delete dd_mod.order
|
115
|
+
batch.update(ref, {
|
116
|
+
collections : arrayUnion(coll_handle),
|
117
|
+
search : arrayUnion(`col:${coll_handle}`),
|
118
|
+
[`discounts.${dd_mod.code}`]: dd_mod
|
119
|
+
})
|
120
|
+
})
|
121
|
+
await batch.commit()
|
122
|
+
} catch (e) {
|
123
|
+
throw 'Products update failed: ' + String(e)
|
124
|
+
}
|
125
|
+
|
126
|
+
try {
|
127
|
+
// now, create a new collection
|
128
|
+
/**@type {import('./js-docs-types').CollectionData} */
|
129
|
+
const col_discount = {
|
130
|
+
desc : dd.desc,
|
131
|
+
handle : coll_handle,
|
132
|
+
title : dd.title,
|
133
|
+
media : dd.media,
|
134
|
+
tags : dd.tags,
|
135
|
+
attributes: dd.attributes,
|
136
|
+
createdAt: Date.now()
|
137
|
+
}
|
138
|
+
|
139
|
+
await this.context.collections.set(
|
140
|
+
col_discount.handle, col_discount
|
141
|
+
)
|
142
|
+
// await this.update(discount_data.code, { _published: coll_handle })
|
143
|
+
} catch (e) {
|
144
|
+
throw 'Collection creation failed: ' + String(e)
|
145
|
+
}
|
146
|
+
|
147
|
+
}
|
148
|
+
|
149
|
+
}
|
package/src/images.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import { collection_base } from './utils.api.fetch.js';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Base `images` **CRUD**
|
6
|
+
*
|
7
|
+
* @extends {collection_base<
|
8
|
+
* import('@storecraft/core/v-api').ImageTypeUpsert,
|
9
|
+
* import('@storecraft/core/v-api').ImageType>
|
10
|
+
* }
|
11
|
+
*/
|
12
|
+
export default class Images extends collection_base {
|
13
|
+
|
14
|
+
/**
|
15
|
+
*
|
16
|
+
* @param {StorecraftSDK} sdk
|
17
|
+
*/
|
18
|
+
constructor(sdk) {
|
19
|
+
super(sdk, 'images');
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import {
|
3
|
+
collection_base, fetchApiWithAuth
|
4
|
+
} from './utils.api.fetch.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Base `notifications` **CRUD**
|
8
|
+
*
|
9
|
+
* @extends {collection_base<
|
10
|
+
* import('@storecraft/core/v-api').NotificationTypeUpsert,
|
11
|
+
* import('@storecraft/core/v-api').NotificationType>
|
12
|
+
* }
|
13
|
+
*/
|
14
|
+
export default class Notifications extends collection_base {
|
15
|
+
|
16
|
+
/**
|
17
|
+
*
|
18
|
+
* @param {StorecraftSDK} sdk
|
19
|
+
*/
|
20
|
+
constructor(sdk) {
|
21
|
+
super(sdk, 'notifications');
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
*
|
26
|
+
* @param {import('@storecraft/core/v-api').NotificationTypeUpsert[]} items
|
27
|
+
*/
|
28
|
+
upsertBulk = items => {
|
29
|
+
return fetchApiWithAuth(
|
30
|
+
this.sdk,
|
31
|
+
`${this.base_name}`,
|
32
|
+
{
|
33
|
+
method: 'post',
|
34
|
+
body: JSON.stringify(items),
|
35
|
+
headers: {
|
36
|
+
'Content-Type': 'application/json'
|
37
|
+
}
|
38
|
+
}
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
meta = () => {
|
43
|
+
return this.get('_meta')
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Test if backend moght have new data economically
|
48
|
+
* @returns {Promise<boolean>}
|
49
|
+
*/
|
50
|
+
hasChanged = async () => {
|
51
|
+
try {
|
52
|
+
// try cache
|
53
|
+
const cached = await this.list([], 50, true, false)
|
54
|
+
if (cached.length==0)
|
55
|
+
return true
|
56
|
+
|
57
|
+
// compute how many latest updates with max timestamp in cache
|
58
|
+
const max_updated = cached.reduce(
|
59
|
+
(p, c) => {
|
60
|
+
const updatedAt = c[1]?.updatedAt
|
61
|
+
|
62
|
+
if(updatedAt==p.timestamp)
|
63
|
+
p.count+=1
|
64
|
+
else if(updatedAt>p.timestamp)
|
65
|
+
p.count=1
|
66
|
+
|
67
|
+
p.timestamp = Math.max(updatedAt ?? -1, p.timestamp)
|
68
|
+
return p
|
69
|
+
},
|
70
|
+
{
|
71
|
+
timestamp: 0,
|
72
|
+
count: 0
|
73
|
+
}
|
74
|
+
)
|
75
|
+
|
76
|
+
// now, use a light count query to the database
|
77
|
+
const count = await this.context.db.col(NAME).count(
|
78
|
+
{
|
79
|
+
where: [
|
80
|
+
['updatedAt', '>=', max_updated.timestamp]
|
81
|
+
]
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
// console.log(cached)
|
86
|
+
// console.log('count ', count)
|
87
|
+
// console.log('max_updated ', max_updated)
|
88
|
+
|
89
|
+
if(count > max_updated.count)
|
90
|
+
return true
|
91
|
+
|
92
|
+
return false
|
93
|
+
|
94
|
+
} catch (e) {
|
95
|
+
// error
|
96
|
+
console.error(e)
|
97
|
+
return true
|
98
|
+
}
|
99
|
+
|
100
|
+
}
|
101
|
+
|
102
|
+
}
|
package/src/orders.js
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
import { calculate_pricing } from '@storecraft/core/v-api/con.pricing.logic.js';
|
2
|
+
import { StorecraftSDK } from '../index.js'
|
3
|
+
import { collection_base } from './utils.api.fetch.js';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Base `orders` **CRUD**
|
7
|
+
*
|
8
|
+
* @extends {collection_base<
|
9
|
+
* import('@storecraft/core/v-api').OrderDataUpsert,
|
10
|
+
* import('@storecraft/core/v-api').OrderData>
|
11
|
+
* }
|
12
|
+
*/
|
13
|
+
export default class Orders extends collection_base {
|
14
|
+
|
15
|
+
/**
|
16
|
+
*
|
17
|
+
* @param {StorecraftSDK} sdk
|
18
|
+
*/
|
19
|
+
constructor(sdk) {
|
20
|
+
super(sdk, 'orders');
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* calculate pricing of line items
|
25
|
+
*
|
26
|
+
* @param {import('@storecraft/core/v-api').LineItem[]} line_items
|
27
|
+
* @param {import('@storecraft/core/v-api').DiscountType[]} coupons
|
28
|
+
* @param {import('@storecraft/core/v-api').ShippingMethodType} shipping_method
|
29
|
+
* @param {string} [uid]
|
30
|
+
*/
|
31
|
+
calculatePricing = async (
|
32
|
+
line_items, coupons=[], shipping_method, uid
|
33
|
+
) => {
|
34
|
+
// fetch auto discounts
|
35
|
+
const auto_discounts = await this.sdk.discounts.list(
|
36
|
+
{
|
37
|
+
limit: 100,
|
38
|
+
vql: 'app:automatic'
|
39
|
+
}
|
40
|
+
);
|
41
|
+
|
42
|
+
return calculate_pricing(
|
43
|
+
line_items, auto_discounts, coupons, shipping_method, uid
|
44
|
+
);
|
45
|
+
}
|
46
|
+
|
47
|
+
}
|
package/src/payments.js
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import {
|
3
|
+
fetchApiWithAuth, get, list
|
4
|
+
} from './utils.api.fetch.js';
|
5
|
+
|
6
|
+
/**
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
export default class Payments {
|
10
|
+
|
11
|
+
/** @type {import('../index.js').StorecraftSDK} */
|
12
|
+
#sdk = undefined;
|
13
|
+
|
14
|
+
/**
|
15
|
+
*
|
16
|
+
* @param {StorecraftSDK} sdk
|
17
|
+
*/
|
18
|
+
constructor(sdk) {
|
19
|
+
this.#sdk = sdk;
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
*
|
24
|
+
* @param {string} handle payment gateway `handle`
|
25
|
+
*
|
26
|
+
*
|
27
|
+
* @returns {Promise<import('@storecraft/core/v-api').PaymentGatewayItemGet>}
|
28
|
+
*/
|
29
|
+
get(handle) {
|
30
|
+
return get(this.sdk, 'payments/gateways', handle);
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
*
|
35
|
+
*
|
36
|
+
* @returns {Promise<import('@storecraft/core/v-api').PaymentGatewayItemGet[]>}
|
37
|
+
*/
|
38
|
+
list() {
|
39
|
+
return list(this.sdk, 'payments/gateways');
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
/**
|
44
|
+
*
|
45
|
+
* Consult with the `payment` gateway about the payment
|
46
|
+
* status of an `order`.
|
47
|
+
*
|
48
|
+
*
|
49
|
+
* @param {string} order_id
|
50
|
+
*
|
51
|
+
* @returns {Promise<import('@storecraft/core/v-api').PaymentGatewayStatus>}
|
52
|
+
*/
|
53
|
+
paymentStatusOfOrder(order_id) {
|
54
|
+
return fetchApiWithAuth(
|
55
|
+
this.sdk,
|
56
|
+
`/payments/status/${order_id}`,
|
57
|
+
{
|
58
|
+
method: 'get'
|
59
|
+
}
|
60
|
+
)
|
61
|
+
}
|
62
|
+
|
63
|
+
/**
|
64
|
+
*
|
65
|
+
* Invoke a `payment gateway` action on `order`
|
66
|
+
*
|
67
|
+
*
|
68
|
+
* @param {string} action_handle The `action` handle at the gateway
|
69
|
+
* @param {string} order_id the `id` of the `order`
|
70
|
+
*
|
71
|
+
*
|
72
|
+
* @returns {Promise<import('@storecraft/core/v-api').PaymentGatewayStatus>}
|
73
|
+
*/
|
74
|
+
invokeAction(action_handle, order_id) {
|
75
|
+
return fetchApiWithAuth(
|
76
|
+
this.sdk,
|
77
|
+
`/payments/${action_handle}/${order_id}`,
|
78
|
+
{
|
79
|
+
method: 'post'
|
80
|
+
}
|
81
|
+
)
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
get sdk() {
|
86
|
+
return this.#sdk;
|
87
|
+
}
|
88
|
+
|
89
|
+
}
|
package/src/posts.js
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import { StorecraftSDK } from '../index.js'
|
2
|
+
import { collection_base } from './utils.api.fetch.js';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Base `posts` **CRUD**
|
6
|
+
*
|
7
|
+
* @extends {collection_base<
|
8
|
+
* import('@storecraft/core/v-api').PostTypeUpsert,
|
9
|
+
* import('@storecraft/core/v-api').PostType>
|
10
|
+
* }
|
11
|
+
*/
|
12
|
+
export default class Posts extends collection_base {
|
13
|
+
|
14
|
+
/**
|
15
|
+
*
|
16
|
+
* @param {StorecraftSDK} sdk
|
17
|
+
*/
|
18
|
+
constructor(sdk) {
|
19
|
+
super(sdk, 'posts');
|
20
|
+
}
|
21
|
+
|
22
|
+
}
|