@leaddreamer/inventorylogic 0.0.3-beta.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.
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Typedefs, constants, support functions and database operations related to usage Units
3
+ * and conversions
4
+ * @module Utilities
5
+ */
6
+ import {
7
+ collectRecordsByFilter,
8
+ typedIdFromChild,
9
+ typedRefPathFromChild,
10
+ fetchRecord,
11
+ collectRecords,
12
+ writeBack,
13
+ writeRecord,
14
+ } from "@leaddreamer/firebase-wrapper";
15
+ import { Forms } from "@leaddreamer/staticforms";
16
+ import { ADDRESSES } from "../boilerplate";
17
+
18
+ //////////////////////////////////////////////////////////////////////
19
+
20
+ /**
21
+ * pulls the document Id from a passed refPath string (firebase dependent)
22
+ * @param {!string} refPath
23
+ * @returns {string} Id
24
+ */
25
+ function stripDocIdFromRefPath(refPath) {
26
+ return refPath.split("/").pop();
27
+ }
28
+
29
+ /**
30
+ * used generic for constructing forms for input and display
31
+ * @param {!string} type refers to the sub-collection name
32
+ * @param {!string} link refers to the linking "value" - a documentID
33
+ * @param {?string} refPath optionally refers to the "/" separate path to
34
+ * the parent document in firebase
35
+ * @returns {Promise.RecordDocument}
36
+ */
37
+ export async function fetchLinkedItem(type, link, refPath = null) {
38
+ return fetchRecord(type, link, refPath);
39
+ //the "link" in this case is the document Id
40
+ }
41
+
42
+ /**
43
+ * some items are stored in the database as a single-record collection, using
44
+ * the same Id as the parent
45
+ * @param {!string} type refers to the sub-collection name
46
+ * @param {!string} refPath refers to the "/" separate path to the required
47
+ * parent document in firebase
48
+ * @returns {Promise.RecordDocument}
49
+ */
50
+ export async function fetchSubItem(type, refPath) {
51
+ let result;
52
+ const commonId = stripDocIdFromRefPath(refPath);
53
+ try {
54
+ result = await fetchRecord(type, commonId, refPath);
55
+ } catch (err) {
56
+ //if there is no record, create a skeleton record
57
+ result = Promise.resolve({
58
+ Id: commonId,
59
+ refPath: `${refPath}/${type}/${commonId}`,
60
+ });
61
+ }
62
+ return result;
63
+ //returns a PROMISE
64
+ //subrecord items are in the named sub-collection with the parent's Id
65
+ //these collections have ONLY one document
66
+ }
67
+
68
+ /**
69
+ * returns an entire sub-collection by "type" (sub-collection name).
70
+ * If refpath is omitted, assumes "type" is a top-level collection
71
+ * @param {!string} type refers to the sub-collection name
72
+ * @param {?string} refPath optionally refers to the "/" separate path to
73
+ * the parent document in firebase
74
+ * @returns {Promise.Array.RecordDocument}
75
+ */
76
+ export async function fetchType(type, refPath = null) {
77
+ const tablePath = type;
78
+
79
+ if (type === ADDRESSES && !refPath) return null;
80
+
81
+ return collectRecords(tablePath, refPath);
82
+ //returns a PROMISE
83
+ //subrecord items are in the named sub-collection
84
+ }
85
+
86
+ /**
87
+ * returns a Promise which resolves to an array of all Type's whose
88
+ * name begins with the provided prompt, optionally limited to a provided number
89
+ * CASE SENSITIVE FOR NOW
90
+ * @param {string} type type of record to search
91
+ * @param {Record} parent parent object of records, if any
92
+ * @param {?string} prompt Used to query for matching records
93
+ * @param {?string|number} limit Used to limit the number of results
94
+ * @returns {Promise.Array.OrganizationType}
95
+ */
96
+ export async function searchType(
97
+ type,
98
+ parent = null,
99
+ prompt = null,
100
+ limit = null,
101
+ ) {
102
+ const field = Forms.SearchBy[type];
103
+ let filterArray =
104
+ prompt && prompt.length
105
+ ? [{ fieldRef: field, opStr: ">=", value: prompt }]
106
+ : null;
107
+ const sortArray = [
108
+ {
109
+ fieldRef: field,
110
+ dirStr: "asc",
111
+ },
112
+ ];
113
+ return collectRecordsByFilter(
114
+ type,
115
+ parent?.refPath,
116
+ filterArray,
117
+ sortArray,
118
+ limit,
119
+ );
120
+ }
121
+
122
+ /**
123
+ * creates and returns a minimal record from an Id and `type`
124
+ * @param {!string} Id
125
+ * @param {!string} Type
126
+ * @returns {AccountType}
127
+ */
128
+ export const recordByIdAndType = (Id, Type) => {
129
+ return {
130
+ Id: Id,
131
+ refPath: `/${Type}/${Id}`,
132
+ };
133
+ };
134
+
135
+ /**
136
+ * builds a representation of a parent from a child, by type
137
+ * @param {string} type
138
+ * @param {Record} child
139
+ * @returns {Record}
140
+ */
141
+
142
+ export function typedRecordFromChild(child, type) {
143
+ return {
144
+ Id: typedIdFromChild(child, type),
145
+ refPath: typedRefPathFromChild(child, type),
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Firebase query support - builds default sort options
151
+ * @param {!string} type
152
+ * @returns {Array.SortObject}
153
+ */
154
+ export function typedSortArray(type) {
155
+ switch (type) {
156
+ case ADDRESSES:
157
+ return [{ fieldRef: "address_line_1", dirStr: "asc" }];
158
+ default:
159
+ return [{ fieldRef: "name", dirStr: "asc" }];
160
+ }
161
+ }
162
+
163
+ /**
164
+ * generic form data processing for database by "type" (collection name)
165
+ * @param {RecordDocument} item
166
+ * @param {!string} type refers to the sub-collection name
167
+ * @param {?string} refPath optionally refers to the "/" separate path to
168
+ * the parent document in firebase
169
+ * @returns {Promise.RecordDocument}
170
+ */
171
+ export async function processItemType(
172
+ item,
173
+ type,
174
+ refPath = null,
175
+ batch = null,
176
+ ) {
177
+ switch (type) {
178
+ case ADDRESSES:
179
+ return item?.Id
180
+ ? writeBack(item, batch)
181
+ : writeRecord(type, item, refPath, batch);
182
+ default:
183
+ return Promise.resolve(null);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * fetches a sub-record from the database and returns the result as a summary string
189
+ * @param {!string} link refers to the linking "value" - a documentID
190
+ * @param {!string} type refers to the sub-collection name
191
+ * @param {!string} refPath refers to the "/" separate path to the required
192
+ * parent document in firebase
193
+ * @returns {Promise.string}
194
+ */
195
+ export async function formatLinkedItem(link, type, refPath) {
196
+ const tablePath = type;
197
+ const Id = link; //can also be a partial path ending with Id
198
+ const item = await fetchRecord(tablePath, Id, refPath);
199
+ return summarizeItem(item, type);
200
+ }
201
+
202
+ /**
203
+ * parameterized function to return string summary of an object
204
+ * By default, returns the "name" property of the item.
205
+ * @param {object} item - data object to summarize
206
+ * @param {String|"User"|"Product"|"LineItem"|"Commodities"|"Units"} type
207
+ * - type of the object to summarize
208
+ * @returns {string}
209
+ */
210
+ export function summarizeItem(item, type) {
211
+ //checks for presence in the Forms object
212
+ return Forms.Summarize[type] ? Forms.Summarize[type](item) : (item.name || item.Id);
213
+ }
214
+
215
+ /**
216
+ * Convenience function to mask actual Forms array from the front-end
217
+ * This version returns the "base" item sample for a business-object type,
218
+ * where the keys are the field/property names, and the values are the
219
+ * default values as defined in the business logic
220
+ * @param {string} type
221
+ * @returns {object} keys and default values
222
+ */
223
+ export function baseItem(type) {
224
+ return Forms.Base[type];
225
+ }
226
+
227
+ /**
228
+ * Convenience function to mask actual Forms array from the front-end
229
+ * This version returns the "baseForm" withe keys/properties, and
230
+ * values are strings with ":" separated definitions for EditForm and
231
+ * similar functionality - see "EditForm" for more details
232
+ * @param {string} type
233
+ * @returns {object} keys and default values
234
+ */
235
+ export function baseForm(type) {
236
+ return Forms.BaseForm[type];
237
+ }
238
+
239
+ /**
240
+ * Convenience function to mask actual Forms array from the front-end
241
+ * This version returns the "Data" object with keys/properties, and
242
+ * values are strings with ":" separated definitions for Faker and
243
+ * similar functionality - to generate "fake" simulated data for testing
244
+ * @param {string} type
245
+ * @returns {object} keys and default values
246
+ */
247
+ export function dataForm(type) {
248
+ return Forms?.Data[type] ? Forms.Data[type] : null;
249
+ }
250
+
251
+ /**
252
+ * Convenience function to mask actual Forms array from the front-end
253
+ * This version returns the "createForm" withe keys/properties, and
254
+ * values are strings with ":" separated definitions for EditForm and
255
+ * similar functionality - see "EditForm" for more details
256
+ * Specifically for limited "front-end" use to CREATE new
257
+ * business-objects with the minimum entries necessary
258
+ * @param {string} type
259
+ * @returns {object} keys and default values
260
+ */
261
+ export function createForm(type) {
262
+ return Forms?.CreateForm[type]
263
+ ? Forms.CreateForm[type]
264
+ : null;
265
+
266
+ }
267
+
268
+ /**
269
+ * Convenience function to mask actual Forms array from the front-end
270
+ * This version returns the "createForm" withe keys/properties, and
271
+ * values are strings with ":" separated definitions for EditForm and
272
+ * similar functionality - see "EditForm" for more details
273
+ * Specifically for limited "front-end" use on ACCOUNT business-objects
274
+ * with the minimum entries necessary
275
+ * @param {string} type
276
+ * @returns {object} keys and default values
277
+ */
278
+ export function accountForm(type) {
279
+ return Forms?.AccountForm[type] ? Forms.AccountForm[type] : null;
280
+ }
281
+
282
+ /**
283
+ * Convenience function to mask actual Forms array from the front-end
284
+ * This version returns a FUNCTION to use for saving a business-object
285
+ * to the database - abstracting type-specific features and functionality
286
+ * from the front end
287
+ * @param {string} type
288
+ * @returns {callback}
289
+ */
290
+ export function saveForm(type) {
291
+ return Forms?.Save[type] ? Forms.Save[type] : () => { };
292
+ }
293
+
294
+ /**
295
+ * @function UpdateChange
296
+ * Function Signature for UpdateChange functions
297
+ * @param {object} prev
298
+ * @param {object} value
299
+ * @param {string} itemFor
300
+ * @param {object} fullChoiceObject
301
+ * @returns {object}
302
+ */
303
+
304
+ /**
305
+ * Convenience function to mask actual Forms array from the front-end
306
+ * This version returns a FUNCTION to respond to cross-field dependent
307
+ * chnages during editing with EditForm, reactdatagrid, etc
308
+ * @param {string} type
309
+ * @returns {callback}
310
+ */
311
+ export function updateChangeForm(type) {
312
+ //if there *is* a special change function, return it, else
313
+ //return a simple function to return the new value directly
314
+ return Forms?.UpdateChange[type]
315
+ ? Forms.UpdateChange[type] //returns a FUNCTION
316
+ : (prev, value, itemFor) => {
317
+ return {
318
+ ...prev,
319
+ [itemFor]: value
320
+ };
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Returns an object whose keys are the available choices for a
326
+ * business-object field, and whose values represent the sort order
327
+ * Most fieldname have no such choices. Both the definitions and
328
+ * usage are defined in business logic elsewhere
329
+ * @param {string} fieldname which business type is being processes
330
+ * @returns {object}
331
+ */
332
+ export function choicesForm(fieldname) {
333
+ return Forms.Choices[fieldname]
334
+ ? Forms.Choices[fieldname]
335
+ : {};
336
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared constants and symbols
3
+ * @module Boilerplate
4
+ */
5
+
6
+ /////////////////////////////////////////////////////////////
7
+ // generic constants
8
+ export const UNSUBSCRIBEKEYS = `unsubscribeKeys`;
9
+ export const ADDRESSES = "Addresses";
10
+ export const COMMODITY = `Commodity`;
11
+ export const COMMODITIES = COMMODITY;
12
+ export const LINEITEM = `LineItem`;
13
+ export const LINEITEMS = LINEITEM;
14
+ export const LABORRATES = `LaborRates`;
15
+ export const PRODUCT = `Products`;
16
+ export const PRODUCTS = PRODUCT;
17
+ export const STAGE = `stages`;
18
+ export const STAGES = STAGE;
19
+ export const MATERIAL = `material`;
20
+ export const MATERIALS = MATERIAL;
21
+ export const PAYMENT = `Payment`;
22
+ export const PAYMENTS = PAYMENT;
23
+ export const RECEIPTS = `Receipts`;
24
+ export const CARDS = `Cards`;
25
+ export const UNITS = "units";
26
+ export const UNIT = UNITS;
27
+ export const USER = "User";
28
+ export const USERS = USER;
29
+
30
+ export const MARKUPS = "markups";
31
+
32
+ export const BASE = `base`;
33
+ export const HIGHVALUE = `highValue`;
34
+ export const SERVICE = `service`;
35
+
36
+ export const FABRICATION = `fabrication`;
37
+ export const WHOLESALE = `wholesale`;
38
+ export const RETAIL = `retail`;
39
+
40
+ export const fakerJSON = {
41
+ COMPONENT_RANGE: {
42
+ min: 0.01,
43
+ max: 20.0,
44
+ dec: 2,
45
+ symbol: "$",
46
+ },
47
+ COMPONENT_COUNT_RANGE: { min: 1, max: 10 },
48
+ ISBN_LENGTH: { variant: 10 },
49
+ };
50
+
51
+ export const COMPONENT_RANGE = "COMPONENT_RANGE";
52
+ export const COMPONENT_COUNT_RANGE = "COMPONENT_COUNT_RANGE";
53
+ export const ISBN_LENGTH = "ISBN_LENGTH";
54
+
55
+ //end constants
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A collection of Business logic and database functions. Shared between ReactJS
3
+ * frontEnd and NodeJS BackEnd
4
+ * @module InventoryLogic
5
+ */
6
+ export * from "./boilerplate";
7
+ export * from "./Commodities";
8
+ export * from "./LineItem";
9
+ export * from "./Payment";
10
+ export * from "./User";
11
+ export * from "./Product";
12
+ export * from "./Markups";
13
+ export * from "./units";
14
+ export * from "./Utilities";
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Typedefs, constants, support functions and database operations related to usage Units
3
+ * and conversions
4
+ * @module Units
5
+ */
6
+ import { writeRecord, writeBack } from "@leaddreamer/firebase-wrapper";
7
+ import { Forms } from "@leaddreamer/staticforms";
8
+
9
+ import { UNITS } from "../boilerplate";
10
+
11
+ //////////////////////////////////////////////////////////////////////
12
+ // Constants
13
+ /**
14
+ * A structure to hold Unit name and conversion information
15
+ * This does NOT deal with length/area/volume changes
16
+ * @typedef {object} Unit
17
+ * @property {string} Id database record Id - random but unique
18
+ * @property {string} refPath database record/document storage path
19
+ * @property {string} unit text version of the unit name
20
+ * @property {number} ratio numerical conversion highValue
21
+ * @property {string} otherUnit other unit to reference against - "name" unit is "ratio" of "other" unit
22
+ * @property {string} system measurement system - imperial, metric, time
23
+ */
24
+
25
+ /**
26
+ * @readonly
27
+ * @constant
28
+ * @type {Unit}
29
+ * @default
30
+ */
31
+ const UnitDefault = {
32
+ Id: null,
33
+ refPath: null,
34
+ unit: null,
35
+ ratio: 1.0,
36
+ otherUnit: null,
37
+ system: null,
38
+ };
39
+
40
+ /**
41
+ * @readonly
42
+ * @constant
43
+ * @type {Unit}
44
+ * @default
45
+ */
46
+ const UnitForm = {
47
+ unit: "text",
48
+ ratio: "number",
49
+ otherUnit: `lookup:${UNITS}`,
50
+ system: "string",
51
+ };
52
+
53
+ /**
54
+ * @readonly
55
+ * @constant
56
+ * @type {Unit}
57
+ * @default
58
+ */
59
+ const UnitData = {
60
+ unit: "science.unit",
61
+ otherUnit: "science.unit",
62
+ ratio: 1,
63
+ };
64
+
65
+ Forms.Base[UNITS] = UnitDefault;
66
+ Forms.BaseForm[UNITS] = UnitForm;
67
+ Forms.CreateForm[UNITS] = UnitForm;
68
+ Forms.Data[UNITS] = UnitData;
69
+ Forms.Summarize[UNITS] = summarizeUnit;
70
+ Forms.Save[UNITS] = saveUnit;
71
+ Forms.SearchBy[UNITS] = "name";
72
+
73
+ //////////////////////////////////////////////////////////////////////
74
+ // record operations
75
+ /**
76
+ * Saves a default Stage Settings object to the database
77
+ * @property {Unit} unit
78
+ * @returns {Promise<void>}
79
+ */
80
+ export async function saveUnit(unit) {
81
+ return writeRecord(UNITS, unit);
82
+ }
83
+
84
+ //////////////////////////////////////////////////////////////////////
85
+ // utilities
86
+
87
+ /**
88
+ * Returns a standardized formatted name string
89
+ * @param {Unit}
90
+ * @returns {string} formatted name string
91
+ */
92
+ function summarizeUnit(unit) {
93
+ return `${unit?.name || unit?.Id}`;
94
+ }
package/index.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Business Logic for the PaaS, wrapped
3
+ * around FirebaseWrapper, to be shared between Back and Front End.
4
+ * This particular library only provides the business "logic" - not browser
5
+ * services.
6
+ * @module InventoryLogic
7
+ */
8
+
9
+ import FirebaseWrapper from "@leaddreamer/firebase-wrapper";
10
+ import { setLogger } from "@leaddreamer/genericutilities";
11
+
12
+ /**
13
+ * only authDomain, databaseURL and storageBucket are present when
14
+ * called from a cloud environment
15
+ * @typedef {object} FirebaseConfigObject
16
+ * @property {!string} apiKey required api Key from Firebase Console,
17
+ * @property {!string} appId required app ID from Firebase Console
18
+ * @property {!string} projectId required Firebase projectID from Firebase
19
+ * console
20
+ * @property {?string} authDomain (optional) auth domain from Firebase Console
21
+ * @property {?string} databaseURL (optional) Firestore database URL from Firebase
22
+ * console
23
+ * @property {?string} storageBucket: (optional) URL of Firestore Storage Bucket
24
+ * @property {?string} messagingSenderId: (optional) ID for Messaing service from
25
+ * Firebase Console
26
+ * @property {?string} measurementId: (optional) Analytics/Measurement ID from Firebase
27
+ * Console
28
+ * @property {?string} mapsAPIKey (optional) App ID for Google Maps API, from Google
29
+ */
30
+
31
+ /**
32
+ * all-in-one wrapper for a solid subset of CLIENT-SIDE Firebase
33
+ * functions, with a consistent interface. There is a parallel set for
34
+ * ADMIN-SIDE functions as well.
35
+ * Call/initialize with Firebase Configuration settings in an object as
36
+ * described below
37
+ * @param {Firebase} firebase
38
+ * @param {FirebaseConfigObject} config Firebase Admin object
39
+ * @param {callback} thisLogger
40
+ * @returns {Promise.Firebase.app}
41
+ *
42
+ * @example
43
+ * ```
44
+ * //this specifically loads ALL the subsections, specifically for
45
+ * //the Browser. See later (tbd) notes for NodeJS
46
+ *
47
+ * import FirebaseWrapper from "@leaddreamer/firebase-wrapper";
48
+ * FirebaseWrapper(config); //see below
49
+ * export * from "@leaddreamer/firebase-wrapper";
50
+ * ```
51
+ */
52
+ export function databaseStart(firebase, config, thisLogger = null) {
53
+ setLogger(thisLogger);
54
+ return FirebaseWrapper(firebase, config, thisLogger);
55
+ }
56
+
57
+ export * from "./business";
58
+ export * from "@leaddreamer/firebase-wrapper";
59
+ export * from "@leaddreamer/genericutilities";
60
+ export * from "@leaddreamer/staticforms";
61
+ export default databaseStart;
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@leaddreamer/inventorylogic",
3
+ "engines": {
4
+ "node": ">=22"
5
+ },
6
+ "version": "0.0.3-beta.0",
7
+ "description": "Business & Database Logic for Inventory Services",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/SaltSweetSpirits/inventoryLogic.git"
11
+ },
12
+ "homepage": "https://github.com/SaltSweetSpirits/inventoryLogic#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/SaltSweetSpirits/inventoryLogic/issues",
15
+ "email": "info@dreamsandlogic.com"
16
+ },
17
+ "license": "MIT",
18
+ "author": {
19
+ "name": "Tracy R. Hall, Dreams and Logic",
20
+ "email": "tracy@dreamsandlogic.com",
21
+ "url": "http://dreamsandlogic.com"
22
+ },
23
+ "files": [
24
+ "*.js",
25
+ "**/*.js",
26
+ "*.md",
27
+ "/*/*.md"
28
+ ],
29
+ "module": "index.js",
30
+ "scripts": {
31
+ "reinstall": "rm -rf node_modules && npm install",
32
+ "mybuild": "parcel build",
33
+ "rebuild": "$npm_execpath version patch --git-tag-version && $npm_execpath run docs",
34
+ "beta:rebuild": "$npm_execpath version prerelease --git-tag-version --preid=beta && $npm_execpath run docs",
35
+ "release:rebuild": "$npm_execpath version minor --git-tag-version && $npm_execpath run docs",
36
+ "myprepublishOnly": "$npm_execpath run build",
37
+ "make_docs": "jsdoc2md -c jsdoc.conf.json --template README.hbs --files *.js ./business/*.js ./business/*/*.js > README.md",
38
+ "docs": "$npm_execpath run make_docs",
39
+ "beta:publish": "$npm_execpath publish --tag=beta --access=restricted",
40
+ "package:publish": "$npm_execpath publish --access=restricted",
41
+ "dry:publish": "$npm_execpath publish --dry-run"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "dependencies": {
47
+ "@leaddreamer/firebase-wrapper": "^2.1.1-beta.11",
48
+ "@leaddreamer/genericutilities": "^0.1.6",
49
+ "@leaddreamer/staticforms": "^1.0.2-beta.0",
50
+ "lodash.clonedeep": "4.5.0",
51
+ "mathjs": "13.2.3",
52
+ "uuid": "8.3.2"
53
+ },
54
+ "peerDependencies": {
55
+ "firebase": "11.10.0",
56
+ "firebase-admin": "13.4.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "firebase-admin": {
60
+ "optional": true
61
+ },
62
+ "firebase": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "accounting-js": "2.0.3",
68
+ "jsdoc-to-markdown": "9.1.1",
69
+ "parcel": "latest"
70
+ },
71
+ "keywords": []
72
+ }