@agung_dhewe/webapps 1.1.2

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 (130) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +2 -0
  3. package/jsconfig.json +10 -0
  4. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.css +2 -0
  5. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +11 -0
  6. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +1 -0
  7. package/libs/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
  8. package/libs/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
  9. package/libs/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
  10. package/libs/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
  11. package/libs/fgta5js-dist/fonts/karla.css +142 -0
  12. package/libs/webmodule/module-edit.css +163 -0
  13. package/libs/webmodule/module-footer.css +22 -0
  14. package/libs/webmodule/module-list.css +25 -0
  15. package/libs/webmodule/module.css +52 -0
  16. package/libs/webmodule/module.js +195 -0
  17. package/libs/webmodule/pagehelper.mjs +45 -0
  18. package/modules/generator/appgen-components.mjs +142 -0
  19. package/modules/generator/appgen-icons.mjs +6 -0
  20. package/modules/generator/appgen-io.mjs +784 -0
  21. package/modules/generator/appgen-ui-search.mjs +173 -0
  22. package/modules/generator/appgen-ui-unique.mjs +153 -0
  23. package/modules/generator/appgen-ui.mjs +1181 -0
  24. package/modules/generator/generator-context.mjs +18 -0
  25. package/modules/generator/generator-designtemplate.html +1508 -0
  26. package/modules/generator/generator-ext.html +0 -0
  27. package/modules/generator/generator-ext.mjs +3 -0
  28. package/modules/generator/generator.css +642 -0
  29. package/modules/generator/generator.mjs +195 -0
  30. package/modules/generator/generator.png +0 -0
  31. package/modules/generator/generatorEdit.html +185 -0
  32. package/modules/generator/generatorEdit.mjs +238 -0
  33. package/modules/generator/generatorList.html +32 -0
  34. package/modules/generator/generatorList.mjs +243 -0
  35. package/modules/login/login.css +11 -0
  36. package/modules/login/login.html +12 -0
  37. package/modules/login/login.mjs +111 -0
  38. package/package.json +46 -0
  39. package/percobaan/simmpan-ke-minio.js +24 -0
  40. package/src/api.js +80 -0
  41. package/src/apis/generator.api.js +226 -0
  42. package/src/apis/login.api.js +109 -0
  43. package/src/bucket.js +24 -0
  44. package/src/context.js +26 -0
  45. package/src/datalog.sql +22 -0
  46. package/src/datarecords.js +0 -0
  47. package/src/db.js +61 -0
  48. package/src/generator/createApiExtenderModule.js +54 -0
  49. package/src/generator/createApiModule.js +218 -0
  50. package/src/generator/createIcon.js +62 -0
  51. package/src/generator/createInfoAboutExtender.js +42 -0
  52. package/src/generator/createInfoLogs.js +41 -0
  53. package/src/generator/createInfoRecordExtender.js +41 -0
  54. package/src/generator/createModuleContext.js +48 -0
  55. package/src/generator/createModuleDetilEditHtml.js +110 -0
  56. package/src/generator/createModuleDetilEditMjs.js +172 -0
  57. package/src/generator/createModuleDetilListHtml.js +146 -0
  58. package/src/generator/createModuleDetilListMjs.js +73 -0
  59. package/src/generator/createModuleEjs.js +51 -0
  60. package/src/generator/createModuleExtenderHtml.js +43 -0
  61. package/src/generator/createModuleExtenderMjs.js +43 -0
  62. package/src/generator/createModuleHeaderEditHtml.js +148 -0
  63. package/src/generator/createModuleHeaderEditMjs.js +197 -0
  64. package/src/generator/createModuleHeaderListHtml.js +144 -0
  65. package/src/generator/createModuleHeaderListMjs.js +67 -0
  66. package/src/generator/createModuleMjs.js +67 -0
  67. package/src/generator/createModuleRollup.js +42 -0
  68. package/src/generator/createProgramData.js +96 -0
  69. package/src/generator/createTable.js +156 -0
  70. package/src/generator/ddl.js +475 -0
  71. package/src/generator/helper.js +149 -0
  72. package/src/generator/templates/__rollup-module.ejs +90 -0
  73. package/src/generator/templates/api-extender-module.js.ejs +0 -0
  74. package/src/generator/templates/api-module.js.ejs +818 -0
  75. package/src/generator/templates/module-context.ejs +16 -0
  76. package/src/generator/templates/module-ext-about.ejs +1 -0
  77. package/src/generator/templates/module-ext-record.ejs +1 -0
  78. package/src/generator/templates/module-ext.html.ejs +3 -0
  79. package/src/generator/templates/module-ext.mjs.ejs +21 -0
  80. package/src/generator/templates/module-logs.ejs +14 -0
  81. package/src/generator/templates/module.ejs.ejs +48 -0
  82. package/src/generator/templates/module.mjs.ejs +256 -0
  83. package/src/generator/templates/moduleDetilEdit.html.ejs +34 -0
  84. package/src/generator/templates/moduleDetilEdit.mjs.ejs +792 -0
  85. package/src/generator/templates/moduleDetilList.html.ejs +26 -0
  86. package/src/generator/templates/moduleDetilList.mjs.ejs +319 -0
  87. package/src/generator/templates/moduleHeaderEdit.html.ejs +53 -0
  88. package/src/generator/templates/moduleHeaderEdit.mjs.ejs +807 -0
  89. package/src/generator/templates/moduleHeaderList.html.ejs +24 -0
  90. package/src/generator/templates/moduleHeaderList.mjs.ejs +308 -0
  91. package/src/generator/templates/sqlAddField.ejs +3 -0
  92. package/src/generator/templates/sqlAddForeignKey.ejs +12 -0
  93. package/src/generator/templates/sqlAddUniqueIndex.ejs +4 -0
  94. package/src/generator/templates/sqlCreateTable.ejs +9 -0
  95. package/src/generator/templates/sqlDropForeignKey.ejs +3 -0
  96. package/src/generator/templates/sqlDropUniqueIndex.ejs +4 -0
  97. package/src/generator/templates/sqlModifyField.ejs +6 -0
  98. package/src/generator/trygenerate.js +83 -0
  99. package/src/generator/worker.js +389 -0
  100. package/src/helper.js +82 -0
  101. package/src/logger.js +39 -0
  102. package/src/router.js +84 -0
  103. package/src/routers/defaultLoginApi.js +29 -0
  104. package/src/routers/defaultLoginAsset.js +18 -0
  105. package/src/routers/defaultLoginPage.js +36 -0
  106. package/src/routers/defaultRootIndex.js +16 -0
  107. package/src/routers/downloadHandler.js +51 -0
  108. package/src/routers/fileUploadApi.js +15 -0
  109. package/src/routers/generatorApi.js +30 -0
  110. package/src/routers/generatorAsset.js +18 -0
  111. package/src/routers/generatorPage.js +37 -0
  112. package/src/routers/handleError.js +43 -0
  113. package/src/routers/handleModuleNotfound.js +12 -0
  114. package/src/routers/moduleApi.js +34 -0
  115. package/src/routers/modulePage.js +102 -0
  116. package/src/sequencerdoc.js +311 -0
  117. package/src/sequencerline.js +214 -0
  118. package/src/session.js +57 -0
  119. package/src/startup.js +59 -0
  120. package/src/webapps.js +239 -0
  121. package/src/workermanager.js +83 -0
  122. package/templates/_lib_debug.ejs +11 -0
  123. package/templates/_lib_production.ejs +5 -0
  124. package/templates/application.page.ejs +143 -0
  125. package/templates/generator.page.ejs +131 -0
  126. package/templates/index.page.ejs +24 -0
  127. package/templates/login.page.ejs +102 -0
  128. package/templates/moduleError.ejs +16 -0
  129. package/templates/moduleNotfound.ejs +14 -0
  130. package/webapps.code-workspace +11 -0
@@ -0,0 +1,51 @@
1
+ import Api from '../api.js'
2
+ import bucket from '../bucket.js'
3
+
4
+ export async function publicDownloadHandler(req, res, next) {
5
+ // hanya bisa dari public bucket
6
+ const bucketname = 'public'
7
+
8
+ // test: /images/profiles/agung-lurik-jogja.jpg
9
+ const objectname = req.query.path;
10
+ if (objectname==null) {
11
+ res.send('object tidak ditemukan')
12
+ return
13
+ }
14
+
15
+ const stat = await bucket.statObject(bucketname, objectname);
16
+ const contentType = stat.metaData['content-type']
17
+ const originalname = stat.metaData['originalname']
18
+
19
+ res.setHeader('Content-Type', contentType);
20
+ res.setHeader('Content-Disposition', `attachment; filename="${originalname}"`);
21
+
22
+ // Stream file dari MinIO ke response
23
+ const stream = await bucket.getObject(bucketname, objectname);
24
+ stream.pipe(res);
25
+
26
+ }
27
+
28
+
29
+
30
+ export async function privateDownloadHandler(req, res, next) {
31
+ // harus login
32
+ const { bucketname, objectname } = req.body
33
+
34
+ try {
35
+ Api.cekLogin(req)
36
+
37
+ const stat = await bucket.statObject(bucketname, objectname);
38
+ const contentType = stat.metaData['content-type']
39
+ const originalname = stat.metaData['originalname']
40
+
41
+ res.setHeader('Content-Type', contentType);
42
+ res.setHeader('Content-Disposition', `attachment; filename="${originalname}"`);
43
+
44
+ // Stream file dari MinIO ke response
45
+ const stream = await bucket.getObject(bucketname, objectname);
46
+ stream.pipe(res);
47
+ } catch (err) {
48
+ throw err
49
+ }
50
+
51
+ }
@@ -0,0 +1,15 @@
1
+
2
+
3
+ export async function fileUploadApi(req, res, next) {
4
+
5
+ const moduleName = 'xxxxxx'
6
+ const ModuleClass = await importModule(moduleName)
7
+ const module = new ModuleClass(req, res, next)
8
+
9
+ try {
10
+ const response = await module.handleRequest('upload', req.body)
11
+ res.send(response)
12
+ } catch (err) {
13
+ next(err);
14
+ }
15
+ }
@@ -0,0 +1,30 @@
1
+ import * as helper from './../helper.js'
2
+ import { handleError } from './handleError.js'
3
+
4
+ export async function generatorApi(req, res, next) {
5
+ // res.status(200).send(`{"code":"1", "message":"api not implemented"}`)
6
+ const moduleName = 'generator'
7
+ const methodName = req.params.method
8
+
9
+ try {
10
+
11
+ const ModuleClass = await helper.importApiModule(moduleName)
12
+ const method = helper.kebabToCamel(methodName);
13
+ if (ModuleClass===undefined) {
14
+ throw new Error(`invalid module: '${moduleName}'`)
15
+ }
16
+
17
+ const requestedBody = req.body
18
+ const module = new ModuleClass(req, res, next)
19
+ const result = await module.handleRequest(method, requestedBody)
20
+ const response = {
21
+ code: 0,
22
+ result: result
23
+ }
24
+ res.json(response)
25
+ } catch (err) {
26
+ handleError(err, req, res)
27
+ }
28
+
29
+
30
+ }
@@ -0,0 +1,18 @@
1
+ import context from '../context.js'
2
+ import fs from 'fs/promises';
3
+ import path from 'node:path';
4
+ import * as helper from '../helper.js'
5
+
6
+
7
+ export async function generatorAsset(req, res, next) {
8
+ const __dirname = context.getWebappsDirectory()
9
+ const requestedFile = req.params.requestedAsset;
10
+ const filePath = path.join(__dirname, 'modules', 'generator', requestedFile)
11
+
12
+ const assetExists = await helper.isFileExists(filePath)
13
+ if (assetExists) {
14
+ res.sendFile(filePath)
15
+ } else {
16
+ res.status(404).send(`'${requestedFile}' is not found`)
17
+ }
18
+ }
@@ -0,0 +1,37 @@
1
+ import context from '../context.js'
2
+ import fs from 'fs/promises';
3
+ import path from 'node:path';
4
+ import * as helper from '../helper.js'
5
+
6
+ import { handleError } from './handleError.js';
7
+
8
+ export async function generatorPage(req, res, next) {
9
+ const __dirname = context.getWebappsDirectory()
10
+
11
+ try {
12
+
13
+ const generatorListPath = path.join(__dirname, 'modules', 'generator', 'generatorList.html')
14
+ const generatorEditPath = path.join(__dirname, 'modules', 'generator', 'generatorEdit.html')
15
+ const generatorDesignPath = path.join(__dirname, 'modules', 'generator', 'generator-designtemplate.html')
16
+
17
+ // load halaman html-nya
18
+ const variables = {
19
+ ...helper.createDefaultEjsVariable(req),
20
+ ...{
21
+ generatorListPath,
22
+ generatorEditPath,
23
+ generatorDesignPath
24
+ }
25
+ }
26
+
27
+ const tplFilePath = path.join(context.getWebappsDirectory(), 'templates', 'generator.page.ejs')
28
+ const content = await helper.parseTemplate(tplFilePath, variables)
29
+
30
+ res.status(200).send(content)
31
+ } catch (err) {
32
+ handleError(err, req, res)
33
+ }
34
+
35
+ }
36
+
37
+
@@ -0,0 +1,43 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import * as http from 'node:http'
4
+ import * as path from 'node:path'
5
+
6
+
7
+ export async function handleError(err, req, res) {
8
+ const appName = req.app.locals.appConfig.appName || ''
9
+ const moduleName = req.params.modulename || req.url
10
+ const status = err.status || 500
11
+ const statusText = http.STATUS_CODES[status]
12
+ const code = err.code ?? 1
13
+
14
+ console.log(err)
15
+ console.log(moduleName)
16
+
17
+ const response = {
18
+ code,
19
+ status,
20
+ statusText,
21
+ appName,
22
+ moduleName
23
+ }
24
+
25
+ if (req.method=='POST') {
26
+ // kalau post (api), kirimkan berupa json
27
+ response.message = "API: " + err.message
28
+ res.status(status).json(response)
29
+
30
+ } else {
31
+ // kalau selain post, kirimkan halaman error
32
+ const variables = {
33
+ ...response,
34
+ ...{
35
+ message: err.message
36
+ }
37
+ }
38
+ const tplFilePath = path.join(context.getWebappsDirectory(), 'templates', 'moduleError.ejs')
39
+ const content = await helper.parseTemplate(tplFilePath, variables)
40
+ res.status(status).send(content)
41
+
42
+ }
43
+ }
@@ -0,0 +1,12 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import * as http from 'node:http'
4
+ import * as path from 'node:path'
5
+
6
+ export async function handleModuleNotfound(req, res) {
7
+ const appName = req.app.locals.appConfig.appName || ''
8
+ const moduleName = req.params.modulename
9
+ const tplFilePath = path.join(context.getWebappsDirectory(), 'templates', 'moduleNotfound.ejs')
10
+ const content = await helper.parseTemplate(tplFilePath, {appName, moduleName})
11
+ res.status(404).send(content)
12
+ }
@@ -0,0 +1,34 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import { handleError } from './handleError.js'
4
+ import * as path from 'path'
5
+
6
+
7
+ export async function moduleApi(req, res, next) {
8
+ const moduleName = req.params.modulename;
9
+ const methodName = req.params.method
10
+ const options = {
11
+ apiDir: path.join(context.getRootDirectory(), 'src', 'apis')
12
+ }
13
+
14
+ try {
15
+
16
+ const ModuleClass = await helper.importApiModule(moduleName, options)
17
+ const method = helper.kebabToCamel(methodName);
18
+ if (ModuleClass===undefined) {
19
+ throw new Error(`invalid module: '${moduleName}'`)
20
+ }
21
+
22
+ const requestedBody = req.body
23
+ const module = new ModuleClass(req, res, next)
24
+ const result = await module.handleRequest(method, requestedBody)
25
+ const response = {
26
+ code: 0,
27
+ result: result
28
+ }
29
+ res.json(response)
30
+ } catch (err) {
31
+ handleError(err, req, res)
32
+ }
33
+
34
+ }
@@ -0,0 +1,102 @@
1
+ import context from './../context.js'
2
+ import fs from 'fs/promises';
3
+ import path from 'node:path';
4
+ import * as helper from './../helper.js'
5
+
6
+ import { handleError } from './handleError.js';
7
+
8
+
9
+
10
+ async function getCurrentVersion(filepath) {
11
+ const previousVersionNumber = await fs.readFile(filepath, 'utf8');
12
+ return previousVersionNumber
13
+ }
14
+
15
+ export async function modulePage(req, res) {
16
+ const moduleName = req.params.modulename;
17
+ const fullUrlWithHostHeader = `${req.protocol}://${req.headers.host}${req.originalUrl}`;
18
+ const __rootDir = context.getRootDirectory()
19
+
20
+ const fgta5jsDebugMode = req.app.locals.appConfig.fgta5jsDebugMode
21
+ const fgta5jsVersion = req.app.locals.appConfig.fgta5jsVersion
22
+ const appDebugMode = req.app.locals.appConfig.appDebugMode
23
+
24
+ const moduleDir = path.join(__rootDir, 'public', 'modules', moduleName)
25
+ const ejsPath = path.join(__rootDir, 'public', 'modules', moduleName, `${moduleName}.ejs`)
26
+ const cssPath = path.join(__rootDir, 'public', 'modules', moduleName, `${moduleName}.css`);
27
+
28
+
29
+ // const mjsFileName = appDebugMode ? `${moduleName}.mjs` : `${moduleName}.min.mjs`
30
+ let mjsFileName
31
+ if (appDebugMode) {
32
+ // Default Debug
33
+ if (req.query.mode=='release') {
34
+ const version = await getCurrentVersion(path.join(__rootDir, 'public', 'modules', moduleName, 'version.txt'))
35
+ mjsFileName = `${moduleName}-${version}.min.mjs`
36
+ } else {
37
+ mjsFileName = `${moduleName}.mjs`
38
+ }
39
+ } else {
40
+ // Default Production
41
+ if (req.query.mode=='debug') {
42
+ mjsFileName = `${moduleName}.mjs`
43
+ } else {
44
+ const version = await getCurrentVersion(path.join(__rootDir, 'public', 'modules', moduleName, 'version.txt'))
45
+ mjsFileName = `${moduleName}-${version}.min.mjs`
46
+ }
47
+ }
48
+ const mjsPath = path.join(__rootDir, 'public', 'modules', moduleName, mjsFileName);
49
+
50
+
51
+ const htmlExtenderFile = `${moduleName}-ext.html`
52
+ const htmlExtenderPath = path.join(__rootDir, 'public', 'modules', moduleName, htmlExtenderFile)
53
+
54
+
55
+ const cssExists = await helper.isFileExists(cssPath)
56
+ const mjsExists = await helper.isFileExists(mjsPath);
57
+ const htmlExtenderExists = await helper.isFileExists(htmlExtenderPath);
58
+
59
+ const mjsPrerenderPath = path.join(__rootDir, 'public', 'modules', moduleName, `${moduleName}-prerender.mjs`);
60
+ const mjsPrerenderExists = await helper.isFileExists(mjsPrerenderPath)
61
+
62
+
63
+ const ejsModuleExist = await helper.isFileExists(ejsPath)
64
+
65
+ try {
66
+
67
+ // coba cek request halaman
68
+ const fnParseModuleRequest = context.getFnParseModuleRequest()
69
+ if (typeof fnParseModuleRequest==='function') {
70
+ await fnParseModuleRequest(req, res)
71
+ }
72
+
73
+
74
+ // load halaman html-nya
75
+ if (!ejsModuleExist) {
76
+ const err = new Error(`requested module '${moduleName}' is not found`)
77
+ err.status = 404
78
+ throw err
79
+ }
80
+
81
+ const variables = {
82
+ ...helper.createDefaultEjsVariable(req),
83
+ ...{
84
+ moduleDir,
85
+ ejsPath,
86
+ mjsPrerenderExists,
87
+ cssExists,
88
+ mjsExists,
89
+ mjsFileName,
90
+ htmlExtenderExists,
91
+ htmlExtenderPath,
92
+ }
93
+ }
94
+
95
+ const tplFilePath = path.join(context.getWebappsDirectory(), 'templates', 'application.page.ejs')
96
+ const content = await helper.parseTemplate(tplFilePath, variables)
97
+
98
+ res.status(200).send(content)
99
+ } catch (err) {
100
+ handleError(err, req, res)
101
+ }
102
+ }
@@ -0,0 +1,311 @@
1
+ import sqlUtil from '@agung_dhewe/pgsqlc'
2
+
3
+ const MAX_LENGTH = 19
4
+ const BLOCK_MAX_LENGTH = 5
5
+ const CLUSTER_MAX_LENGTH = 3
6
+ const tablename = "core.sequencer_doc"
7
+
8
+
9
+ export function createSequencerDocument(db, options) {
10
+ return new Sequencer(db, options)
11
+ }
12
+
13
+
14
+ class Sequencer {
15
+
16
+
17
+ #defaultOptions = {
18
+ COMPANY_CODE: '00',
19
+ blockLength: 3,
20
+ clusterLength: 2,
21
+ numberLength: 6
22
+ }
23
+
24
+
25
+ db
26
+ options
27
+
28
+
29
+ constructor(db, opt) {
30
+ this.db = db
31
+ this.options = {
32
+ ...this.#defaultOptions,
33
+ ...opt
34
+ }
35
+ }
36
+
37
+
38
+ setBlock() {
39
+
40
+ }
41
+
42
+ setCluster() {
43
+
44
+ }
45
+
46
+
47
+ async yearly(doc_id, block=0, cluster=0) {
48
+ const self = this
49
+ const db = self.db
50
+ try {
51
+ const { year } = await getDbCurrentDate(db)
52
+ const month = 0
53
+ return await generateId(self, year, month, doc_id, block, cluster)
54
+ } catch (err) {
55
+ throw err
56
+ }
57
+ }
58
+
59
+ async monthly(doc_id, block=0, cluster=0) {
60
+ const self = this
61
+ const db = self.db
62
+ try {
63
+ const { year, month } = await getDbCurrentDate(db)
64
+ return await generateId(self, year, month, doc_id, block, cluster)
65
+ } catch (err) {
66
+ throw err
67
+ }
68
+ }
69
+
70
+ }
71
+
72
+
73
+ function isValidDigitMax(n, length) {
74
+ if (!Number.isInteger(n) || !Number.isInteger(length) || length <= 0) return false;
75
+
76
+ const maxAllowed = Number('9'.repeat(length));
77
+ return n <= maxAllowed;
78
+ }
79
+
80
+
81
+ async function generateId(self, year, month, doc_id, block, cluster) {
82
+ const options = self.options
83
+ const db = self.db
84
+ const searchMap = {
85
+ seqnum: `sequencer_seqnum=\${seqnum}`,
86
+ block: `sequencer_block=\${block}`,
87
+ cluster: 'sequencer_cluster=\${cluster}',
88
+ year: `sequencer_year=\${year}`,
89
+ month: `sequencer_month=\${month}`
90
+ };
91
+
92
+ sqlUtil.connect(db)
93
+
94
+ try {
95
+ if (!Number.isInteger(block)) {
96
+ throw new Error(`block value: '${block}' is not integer`)
97
+ }
98
+
99
+ if (!Number.isInteger(cluster)) {
100
+ throw new Error(`cluster value: '${cluster}' is not integer`)
101
+ }
102
+
103
+ if (block<0 || !isValidDigitMax(block, options.blockLength)) {
104
+ throw new Error(`block value: '${block}' is invalid. max length: ${options.blockLength} `)
105
+ }
106
+
107
+ if (cluster<0 || !isValidDigitMax(cluster, options.clusterLength)) {
108
+ throw new Error(`cluster value: '${cluster}' is invalid. max length: ${options.clusterLength} `)
109
+ }
110
+
111
+
112
+
113
+
114
+ // ambil code doc
115
+ const docparam = { doc_id }
116
+ const sqldoc = `select doc_seqnum from core.doc where doc_id=\${doc_id}`
117
+ const row = await db.oneOrNone(sqldoc, docparam)
118
+ const seqnum = row!=null ? row.doc_seqnum : 0
119
+
120
+
121
+ if (seqnum<0 || seqnum>99) {
122
+ throw new Error(`doc_id: '${doc_id}' has doc seqnum '${seqnum}' that is invalid. doc seqnum have to in range 1-99 `)
123
+ }
124
+
125
+
126
+ // hitung total panjang bigint yang akan dihailkan
127
+ let nlength = 0
128
+ if (month==0) {
129
+ // yearly
130
+ nlength += 2
131
+ } else {
132
+ // montly
133
+ nlength += 4
134
+ }
135
+
136
+ if (seqnum>0) {
137
+ nlength += 2
138
+ }
139
+
140
+ if (block>0) {
141
+ nlength += self.options.blockLength
142
+ }
143
+
144
+ if (cluster>0) {
145
+ nlength += self.options.clusterLength
146
+ }
147
+
148
+
149
+ // 250901000402 0000009
150
+
151
+ const ln = nlength + self.options.numberLength
152
+ if (ln > MAX_LENGTH) {
153
+ throw new Error(`Total length of sequencer (${ln}) is mre than max length allowed(${MAX_LENGTH})`)
154
+ }
155
+
156
+
157
+
158
+
159
+
160
+ // ambil data sequencer
161
+ {
162
+ const criteria = { year, month, seqnum, block, cluster }
163
+ if (block==null) {
164
+ criteria.block = 0
165
+ }
166
+
167
+ if (cluster==null) {
168
+ criteria.cluster = 0
169
+ }
170
+
171
+
172
+ const {whereClause, queryParams} = sqlUtil.createWhereClause(criteria, searchMap)
173
+ // console.log(year, month, whereClause, queryParams)
174
+
175
+ const columns = [
176
+ 'sequencer_id',
177
+ 'sequencer_year',
178
+ 'sequencer_month',
179
+ 'sequencer_seqnum',
180
+ 'sequencer_block',
181
+ 'sequencer_cluster',
182
+ 'sequencer_number',
183
+ 'EXTRACT(YEAR FROM sequencer_lastdate) AS lastyear',
184
+ 'EXTRACT(MONTH FROM sequencer_lastdate) AS lastmonth'
185
+ ]
186
+
187
+ const sql = sqlUtil.createSqlSelect({tablename, columns, whereClause, sort:{}, limit:0, offset:0, queryParams}) + ' for update'
188
+ const row = await db.oneOrNone(sql, queryParams)
189
+
190
+ const obj = {}
191
+
192
+ if (row!=null) {
193
+ // console.log(row)
194
+ obj.sequencer_id = row.sequencer_id
195
+ obj._modifyby = 0
196
+ obj._modifydate = (new Date()).toISOString()
197
+ obj.sequencer_number = row.sequencer_number+1
198
+ const cmd = sqlUtil.createUpdateCommand(tablename, obj, ['sequencer_id'])
199
+ await cmd.execute(obj)
200
+ } else {
201
+ obj._createby = 0
202
+ obj._createdate = (new Date()).toISOString()
203
+ obj.sequencer_year = year,
204
+ obj.sequencer_month = month
205
+ obj.sequencer_seqnum = seqnum
206
+ obj.sequencer_block = block
207
+ obj.sequencer_cluster = cluster
208
+ obj.sequencer_number = 1
209
+ obj.sequencer_lastdate = (new Date()).toISOString()
210
+ obj.sequencer_remark = doc_id
211
+ const cmd = sqlUtil.createInsertCommand(tablename, obj, ['sequencer_id'])
212
+ await cmd.execute(obj)
213
+ }
214
+
215
+ // compose generated id
216
+ // DD05.YYMM.000.00.00000
217
+ const YY = String(year-2000).padStart(2, '0')
218
+ const MM = String(month).padStart(2, '0')
219
+
220
+ const tokendoc = []
221
+ const tokennum = []
222
+
223
+
224
+ if (options.COMPANY_CODE!='00') {
225
+ if (seqnum>0) {
226
+ tokendoc.push(doc_id)
227
+ tokendoc.push(options.COMPANY_CODE)
228
+ }
229
+ } else {
230
+ if (seqnum>0) {
231
+ tokendoc.push(doc_id)
232
+ }
233
+ }
234
+
235
+
236
+ if (month>0) {
237
+ // monthly
238
+ tokendoc.push('.')
239
+ tokendoc.push(YY)
240
+ tokendoc.push(MM)
241
+
242
+ tokennum.push(YY)
243
+ tokennum.push(MM)
244
+ } else {
245
+ // yearly
246
+ tokendoc.push('.')
247
+ tokendoc.push(YY)
248
+
249
+ tokennum.push(YY)
250
+ }
251
+
252
+ if (seqnum>0) {
253
+ tokennum.push(String(seqnum).padStart(2, '0'))
254
+ }
255
+
256
+
257
+
258
+ if (block>0) {
259
+ const codeBlock = String(block).padStart(self.options.blockLength, '0')
260
+ tokendoc.push('.')
261
+ tokendoc.push(codeBlock)
262
+
263
+ tokennum.push(codeBlock)
264
+ }
265
+
266
+ if (cluster>0) {
267
+ const codeCluster = String(cluster).padStart(self.options.clusterLength, '0')
268
+ tokendoc.push('.')
269
+ tokendoc.push(codeCluster)
270
+
271
+ tokennum.push(codeCluster)
272
+ }
273
+
274
+
275
+ tokendoc.push('.')
276
+ tokendoc.push(String(obj.sequencer_number).padStart(self.options.numberLength, '0'))
277
+
278
+ const idpref = tokennum.join('')
279
+ const numlen = MAX_LENGTH - idpref.length
280
+ tokennum.push(String(obj.sequencer_number).padStart(numlen, '0'))
281
+
282
+ const ret = {
283
+ id: tokennum.join(''),
284
+ doc: tokendoc.join('')
285
+ }
286
+
287
+ return ret
288
+ }
289
+
290
+ } catch (err) {
291
+ throw err
292
+ }
293
+ }
294
+
295
+ async function getDbCurrentDate(db) {
296
+ try {
297
+ const sql = "SELECT EXTRACT('year' FROM CURRENT_DATE) AS year, EXTRACT('month' FROM CURRENT_DATE) AS month"
298
+ const row = await db.one(sql)
299
+
300
+ const ret = {
301
+ year: row.year,
302
+ month: row.month
303
+ }
304
+
305
+ return ret
306
+ } catch (err) {
307
+ throw err
308
+ }
309
+ }
310
+
311
+