Compare commits

...

754 Commits

Author SHA1 Message Date
shancheas 064112e731 feat: add clear couch transaction API 2025-04-14 12:06:05 +07:00
shancheas d6a238a224 fix: time not null when save queue 2025-04-03 22:11:19 +07:00
shancheas dc5e938f75 feat: add configuration to show estimation queue time 2025-04-03 21:54:35 +07:00
shancheas eb4da7ccc4 temp: remove multiple admin login validation from queue admin 2025-04-03 21:54:04 +07:00
shancheas 46caaba6bd fix: add error log to whatsapp service 2025-01-30 07:01:52 +07:00
shancheas 7953c7dbbd fix: validate display uuid
continuous-integration/drone/push Build is passing Details
2025-01-23 22:15:26 +07:00
shancheas 6911f6f0a2 fix: don't send whatsapp notification when phone is null
continuous-integration/drone/push Build is passing Details
2025-01-23 22:11:15 +07:00
shancheas 762340a72b fix: throw error when display id is undefined
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-23 21:49:33 +07:00
shancheas 61cbbf81ef feat: add text to speech api
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-16 12:12:26 +07:00
shancheas 4ea53f7088 fix: average time from float to bigint
continuous-integration/drone/push Build is passing Details
2025-01-15 10:49:56 +07:00
shancheas 0548141e5f fix: add optional id when map transaction
continuous-integration/drone/push Build is passing Details
2025-01-13 17:19:50 +07:00
shancheas 29e4dc5400 fix: code not generate because vip pass
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-13 14:10:32 +07:00
shancheas f9d8f85179 fix: moment js when generate
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-13 13:31:19 +07:00
shancheas 769e8174f4 fix: don't create queue from POS
continuous-integration/drone/push Build is passing Details
2025-01-13 12:59:30 +07:00
shancheas 3ace59c450 feat: create queue using API
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-13 12:42:57 +07:00
shancheas 187555a543 fix: play estimation to numeric
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2025-01-03 17:40:21 +07:00
shancheas 551bd12f5b fix: call time stop when time is more than estimation
continuous-integration/drone/push Build is passing Details
2024-12-25 04:57:28 +07:00
shancheas 1692c8234a fix: error when send to null phone number
continuous-integration/drone/push Build is passing Details
2024-12-25 04:26:12 +07:00
shancheas 903b7cfd18 fix: whatsapp notification not show
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-22 09:33:22 +07:00
shancheas 26a6af2044 fix: register queue still sen notification
continuous-integration/drone/push Build is passing Details
2024-12-22 05:42:28 +07:00
shancheas d7ed77934d temp: remove log
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-21 05:26:16 +07:00
shancheas 66720c5b8b feat: implement requiring call notification 2024-12-21 05:20:25 +07:00
shancheas 44e74de315 feat: whatsapp notification
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-21 04:01:54 +07:00
shancheas 82e7879969 feat: add configuration for whatsapp service 2024-12-21 03:56:13 +07:00
shancheas d612b6725a fix: login by new transaction receipt id
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-17 19:27:07 +07:00
shancheas 54b9658075 fix: show queue only same day 2024-12-17 19:26:22 +07:00
shancheas 661dbb8cf2 fix: add peak level
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-10 15:55:27 +07:00
shancheas 6dc6579450 feat: add item id
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
2024-12-10 14:19:24 +07:00
shancheas e3db958e0d fix: error ticket not found when split queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
2024-12-10 14:00:38 +07:00
shancheas d73752252a feat: peak level base on configuration
continuous-integration/drone/push Build is passing Details
2024-12-10 13:51:28 +07:00
shancheas b38c489777 fix: last item queue time
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-10 12:27:34 +07:00
shancheas 8cfc003261 feat: add query name filter to items
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-10 11:57:33 +07:00
shancheas 55e89426d9 feat(SPG-1078): summary all item queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-03 14:27:12 +07:00
shancheas 5f6214eeb6 feat: add max peak level and call prepare call time to item queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-12-03 11:21:44 +07:00
shancheas d71c2096b8 fix: done queue not update call time 2024-12-03 11:05:03 +07:00
shancheas f661276c58 fix: calculate average time when no queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-28 17:18:33 +07:00
shancheas 4a3e77043e fix: parent qty not reduce when split QR
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-28 11:24:31 +07:00
shancheas b4f141e628 feat(SPG-1061): add bundling to queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-26 12:40:02 +07:00
shancheas 9db5c4b326 feat: add queue recommendations
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-26 10:31:06 +07:00
shancheas f7e3d5399c fix(SPG-1055): update QR when customer and phone exist
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-22 18:51:22 +07:00
shancheas 7305dfd068 fix(SPG-1060): order queue by time
continuous-integration/drone/push Build is passing Details
2024-11-22 17:27:05 +07:00
shancheas b4bc31463e fix(SPG-1049): add order to queue item
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-22 14:49:42 +07:00
shancheas 83d53847d7 feat: add estimation time
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-22 10:54:51 +07:00
shancheas e09190df42 fix: time empty when no queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-21 18:48:49 +07:00
shancheas 61045a39ab fix(SPG-1027): total ticket not match
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-21 18:28:25 +07:00
shancheas 60b5bcf638 fix: time calculation customer
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-21 17:51:45 +07:00
shancheas 4eedca12e7 fix(SPG-1044): validate split QR when phone and username exist
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-21 11:31:29 +07:00
shancheas cb452cf5f3 fix(SPG-1045): send rest qty instead all qty 2024-11-21 11:30:31 +07:00
shancheas ea25e0cae1 fix(SPG-1047): merge item queue with same item 2024-11-21 10:39:20 +07:00
shancheas 5e4401a974 fix: queue time string to number
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 18:06:28 +07:00
shancheas c05af5c16b fix: admin queue time
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 17:51:47 +07:00
shancheas 5988a592ac fix: merge new order queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 17:41:29 +07:00
shancheas 1148a72481 fix: total QR header
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 17:33:00 +07:00
shancheas 3b7d7ea80b fix: don't merge queue when customer name is empty
continuous-integration/drone/push Build is passing Details
2024-11-20 14:44:19 +07:00
shancheas 3b19484f29 fix(SPG-1030): merge queue when user is exits
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 12:50:58 +07:00
shancheas 4dc21c4ebd fix(SPG-1036): remove queue if empty
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 11:46:19 +07:00
shancheas 99d0fc8560 fix(SPG-1035): grouping queue information
continuous-integration/drone/push Build is passing Details
2024-11-20 11:38:23 +07:00
shancheas ac3fde14e3 feat: add total_queue_item to summary ticket
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-20 10:40:23 +07:00
shancheas 8d54c686fc fix(SPG-1027): Total QR not same with total ticket 2024-11-20 10:40:00 +07:00
shancheas c0a68db9f1 fix: total activities, now merge by item queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-19 13:33:45 +07:00
shancheas 3cf4fbdada fix: exclude privilege from admin queue 2024-11-19 13:33:29 +07:00
shancheas 9eacb7dca5 feat: add done status queue 2024-11-19 13:16:52 +07:00
shancheas eae529bce9 fix: vip pass queue register for 1 queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-19 11:13:53 +07:00
shancheas a0de16575f fix: empty queue id in time formula
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-15 13:51:12 +07:00
shancheas 53ef4656eb fix: change queue time formula to manager
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-15 12:37:43 +07:00
shancheas ec916ab574 fix: queue time calculation
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-15 11:16:29 +07:00
shancheas 72827aa83e feat: calculate time queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-15 11:05:34 +07:00
shancheas 0e9ae569ba debug: add log time to queue admin
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-15 10:23:06 +07:00
shancheas 37334ecb19 fix: queue admin item not show 2024-11-14 16:10:31 +07:00
shancheas 86c73058fd feat: add information to queue item for display
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-14 15:05:39 +07:00
shancheas fb7f925c78 feat: add session to admin queue 2024-11-14 14:24:56 +07:00
shancheas 2b132c53a8 feat: add average item queue time
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-14 10:06:51 +07:00
shancheas e9535749d4 fix: vip code prefix
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build was killed Details
2024-11-13 18:18:04 +07:00
shancheas 94696e765d fix: request ticket item 2024-11-13 18:17:53 +07:00
shancheas 9805b9903a feat: add pos item ticket
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-13 16:49:05 +07:00
shancheas af9818d44c feat: cancel order, delete queue
continuous-integration/drone/push Build is passing Details
2024-11-13 15:48:54 +07:00
shancheas 2bcd7a34fb feat: create summary ticket function 2024-11-13 15:48:30 +07:00
shancheas 577f8ea9ea feat: login by receipt
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-13 14:30:23 +07:00
shancheas 1878d03c0f feat: vip auto generate queue 2024-11-13 14:30:10 +07:00
shancheas 6807d00cbe fix: add empty user to base 2024-11-13 14:29:35 +07:00
shancheas ad3e3593fd feat: add gate log
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-13 10:00:37 +07:00
shancheas 8e7e43b09d fix: vip from booking generate queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-11 16:34:58 +07:00
shancheas 6c53610ec4 feat: vip auto enter queue
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-11 14:43:15 +07:00
shancheas c129a59d47 feat: merge item queue 2024-11-11 14:29:17 +07:00
shancheas d413f1fa7b fix: QR queue and date booking
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-08 15:13:33 +07:00
shancheas bf5914af92 fix: queue bucket item id
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-06 12:01:49 +07:00
shancheas 28c1ab36da fix: summary ticket without order
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-06 11:38:51 +07:00
shancheas 3ed25e1366 fix: admin queue order item
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-06 11:28:54 +07:00
shancheas 4c403293db fix: admin queue order item
continuous-integration/drone/push Build is passing Details
2024-11-06 11:28:02 +07:00
shancheas dac42b754c fix: missing logic
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-06 11:06:14 +07:00
shancheas 5ef7521e9b feat: add queue active summary
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-05 14:43:04 +07:00
shancheas ba7b81c320 feat: add login by invoice code
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-04 16:34:17 +07:00
shancheas 7137b98043 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-04 15:06:24 +07:00
shancheas 3ddd837622 fix: customer and phone in split queue 2024-11-04 15:06:09 +07:00
firmanr 217362193a Merge pull request 'feat/report-demography' (#113) from feat/report-demography into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #113
2024-11-04 07:08:22 +00:00
Firman Ramdhani a3647b536b feat: update report demography
continuous-integration/drone/push Build is passing Details
2024-11-04 14:01:37 +07:00
shancheas 5f46432327 feat: login customer
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-04 12:35:53 +07:00
shancheas 319d9eecef Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-11-01 13:33:43 +07:00
shancheas 50e7f66bb7 feat: split QR customer 2024-11-01 13:33:25 +07:00
shancheas 492a4ca2ba wip: queue bucket 2024-11-01 13:32:59 +07:00
Supan Adit Pratama 4ed7ecce5e ci: fix filtering
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-30 14:38:11 +07:00
Supan Adit Pratama e6787aed89 ci: fix duplicate step name
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build was killed Details
2024-10-30 14:37:42 +07:00
Supan Adit Pratama 1d54b709b6 ci: build k8s only
continuous-integration/drone/push Build encountered an error Details
continuous-integration/drone/tag Build encountered an error Details
2024-10-30 14:37:07 +07:00
Supan Adit Pratama bd32d4fbdd ci: fix depends
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build was killed Details
2024-10-30 14:34:27 +07:00
Supan Adit Pratama 78fb5b7fac ci: update pipeline for kustomize auto
continuous-integration/drone/push Build encountered an error Details
continuous-integration/drone/tag Build encountered an error Details
2024-10-30 14:33:50 +07:00
shancheas dea9989914 fix: queue not generate from POS
continuous-integration/drone/push Build is passing Details
2024-10-30 13:54:09 +07:00
shancheas c8d0b32cc6 feat: add list order queue
continuous-integration/drone/push Build is passing Details
2024-10-29 14:15:37 +07:00
shancheas 93b1208278 refactor: change code to manager
continuous-integration/drone/push Build is passing Details
2024-10-29 10:30:57 +07:00
shancheas 86251f43a2 fix: change register ticket body
continuous-integration/drone/push Build is passing Details
2024-10-28 17:16:41 +07:00
shancheas 9977a7456a feat: item queue id in response ticket
continuous-integration/drone/push Build is passing Details
2024-10-28 16:03:13 +07:00
shancheas 487f59ae93 feat: add register queue
continuous-integration/drone/push Build is passing Details
2024-10-28 15:09:27 +07:00
shancheas e9de46fff8 fix: change response queue to pagination
continuous-integration/drone/push Build is passing Details
2024-10-25 16:11:43 +07:00
shancheas 5b507a1c3c feat: add queue admin list
continuous-integration/drone/push Build is passing Details
2024-10-25 14:49:56 +07:00
shancheas 143bf76417 fix: ticket item request url
continuous-integration/drone/push Build is passing Details
2024-10-24 16:05:42 +07:00
shancheas ac86289182 feat: add detail item ticket
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-24 13:25:56 +07:00
shancheas 32d4064f0a feat: add detail queue item
continuous-integration/drone/push Build is passing Details
2024-10-23 17:16:28 +07:00
shancheas 01b2796c26 feat: order tickets
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-23 11:56:21 +07:00
shancheas e9d864c922 feat: add login queue customer 2024-10-23 10:30:14 +07:00
shancheas d6c02ac29f fix: on delete queue item
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-22 14:36:14 +07:00
shancheas 4f0b378ec6 fix: missing transaction handler
continuous-integration/drone/push Build encountered an error Details
2024-10-22 13:30:49 +07:00
shancheas efa245048a feat: item queue module
continuous-integration/drone/push Build encountered an error Details
continuous-integration/drone/tag Build is passing Details
2024-10-22 11:47:55 +07:00
shancheas 2d0ccf67f2 WIP: module Queue 2024-10-22 11:47:22 +07:00
shancheas 77cf19c06e fix: unused code 2024-10-22 11:45:44 +07:00
shancheas 77a6afbbbc fix: add video extension
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-21 12:59:44 +07:00
irfan fea0420ae4 Merge pull request 'development' (#112) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #112
2024-10-19 18:35:05 +00:00
shancheas 3eee8d73f4 fix: recap transaction
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-20 01:33:31 +07:00
shancheas 07d2ec3b46 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-17 15:28:01 +07:00
shancheas 8ba5646bb6 fix: show video url in item and vip pass in vip category 2024-10-17 15:27:43 +07:00
irfan ce1aa86944 Merge pull request 'development' (#111) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #111
2024-10-16 15:42:27 +00:00
irfan 4d20955764 Merge pull request 'feat: update filter report' (#110) from feat/update-filter-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #110
2024-10-16 12:31:48 +00:00
Firman Ramdhani 6a8816aa90 feat: update filter report
continuous-integration/drone/push Build is passing Details
2024-10-16 18:31:55 +07:00
shancheas 8f43907091 feat: add vip pass and video url to item
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-16 17:01:47 +07:00
irfan 7afe06e96c Merge pull request 'fix: get tax formula active only' (#109) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #109
2024-10-14 19:18:00 +00:00
shancheas c0a0b2316d fix: get tax formula active only
continuous-integration/drone/push Build is passing Details
2024-10-15 02:17:13 +07:00
irfan 95ee8dce8d Merge pull request 'development' (#108) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #108
2024-10-09 18:22:03 +00:00
Firman Ramdhani 55ddc9b605 feat(SPG-997): add report vip code
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-09 17:59:20 +07:00
Firman Ramdhani e2a6878e71 feat(SPG-997): add report vip code
continuous-integration/drone/push Build is passing Details
2024-10-09 17:48:31 +07:00
Firman Ramdhani f2c409fc35 feat: adjustment default sorting on report income per item and report per item master
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-09 15:58:13 +07:00
Firman Ramdhani 7213e7915b feat: adjustment default sorting on report income per item and report per item master
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build was killed Details
2024-10-09 14:57:20 +07:00
Firman Ramdhani 0e65fb8a9a feat(SPG-992): penyesuaian kolom total tunai di report reconcile
continuous-integration/drone/push Build is passing Details
2024-10-09 14:49:22 +07:00
shancheas 6efe5618cb Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details
2024-10-09 12:49:56 +07:00
shancheas 60167cd807 fix: change bundling item edit from item_id to total_net_price 2024-10-09 12:49:34 +07:00
Firman Ramdhani 0dfaeb2045 feat: add low level order
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-08 20:00:09 +07:00
shancheas 18dc15e442 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-08 16:27:20 +07:00
shancheas 198dcb4933 feat: add discount value to vip code 2024-10-08 16:26:40 +07:00
shancheas 901c67137b feat: calculate discount for bundling 2024-10-08 15:40:54 +07:00
Firman Ramdhani 411458fe4c feat: add pos name and pos number at report reconciliation
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-07 12:58:31 +07:00
Firman Ramdhani d911f80ff9 feat: add pos name and pos number at report reconciliation
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-10-07 10:40:47 +07:00
irfan 79f3966b49 Merge pull request 'development' (#107) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #107
2024-10-06 23:00:03 +00:00
shancheas e6066b534c fix: add capture error when calculate pos formula
continuous-integration/drone/push Build is passing Details
2024-10-07 05:58:45 +07:00
shancheas c5590ab7b1 fix: pos formula calculation
continuous-integration/drone/push Build is passing Details
2024-10-07 05:54:06 +07:00
irfan 1a633cc574 Merge pull request 'development' (#105) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #105
2024-10-04 04:12:22 +00:00
firmanr 1348f5a79b Merge pull request 'feat: create report demography' (#106) from feat/report-realtime into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #106
2024-10-04 03:38:51 +00:00
Firman Ramdhani 90ab3668b4 feat: create report demography
continuous-integration/drone/push Build is passing Details
2024-10-04 10:38:12 +07:00
firmanr 49b98cd56c Merge pull request 'feat: add module report summary' (#104) from feat/report-realtime into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #104
2024-10-01 15:05:38 +00:00
Firman Ramdhani d6ae891de4 feat: add module report summary
continuous-integration/drone/push Build is passing Details
2024-10-01 22:03:59 +07:00
irfan 9026f85a66 Merge pull request 'development' (#103) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #103
2024-09-29 12:01:23 +00:00
shancheas d40261e919 fix: report query from text to uuid
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-29 10:59:55 +07:00
shancheas e1c6b809e4 fix: add cookie when request superset token
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-28 12:45:13 +07:00
irfan c47f1e2616 Merge pull request 'feat: add cancel transaction report' (#102) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #102
2024-09-27 10:17:42 +00:00
shancheas df0536157a feat: add cancel transaction report
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-25 06:40:03 +07:00
irfan 92bf8fc342 Merge pull request 'fix: discount percent calculation' (#101) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #101
2024-09-21 18:10:34 +00:00
shancheas 437793a2a1 fix: discount percent calculation
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build was killed Details
2024-09-22 01:09:54 +07:00
irfan 48a48e6e7a Merge pull request 'development' (#100) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #100
2024-09-21 16:08:58 +00:00
shancheas 22f4e732db fix: transaction NaN without discount
continuous-integration/drone/push Build is passing Details
2024-09-21 23:04:59 +07:00
shancheas 34ae5964c4 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-21 07:24:34 +07:00
shancheas f2fef65f20 fix: change total price to net price 2024-09-21 07:24:16 +07:00
firmanr 039531de3b Merge pull request 'feat: move tipe item' (#99) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #99
2024-09-20 12:01:57 +00:00
Firman Ramdhani 0b8bb72392 feat: move tipe item
continuous-integration/drone/push Build is passing Details
2024-09-20 19:01:18 +07:00
firmanr 256c8f38bd Merge pull request 'feat: update report' (#98) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #98
2024-09-20 11:36:16 +00:00
Firman Ramdhani 109898b076 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-20 18:34:58 +07:00
shancheas b2be2e0160 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-20 18:33:11 +07:00
shancheas b4266d5d68 fix: add discount to calculator 2024-09-20 18:32:52 +07:00
Firman Ramdhani f23a9f3510 feat: update report
continuous-integration/drone/push Build is passing Details
2024-09-20 18:32:17 +07:00
firmanr 91370940d7 Merge pull request 'feat: fix filter report' (#97) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #97
2024-09-20 10:51:25 +00:00
Firman Ramdhani c15b4d8079 feat: fix filter report
continuous-integration/drone/push Build is passing Details
2024-09-20 17:25:28 +07:00
shancheas b16edb73e3 fix: report wrong non bundling profit share key
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-20 13:01:38 +07:00
firmanr ea58096287 Merge pull request 'feat/adjustment-report' (#96) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #96
2024-09-20 04:50:52 +00:00
Firman Ramdhani 1dfcaf7b15 feat(SPG-969): feat set default payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-20 11:50:34 +07:00
Firman Ramdhani 8b58598955 feat(SPG-969): feat set default payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-20 11:49:58 +07:00
firmanr 5eb50c952f Merge pull request 'feat/adjustment-report' (#95) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #95
2024-09-20 04:33:19 +00:00
Firman Ramdhani aaa0ca6f76 feat: fix report bug and create report tax
continuous-integration/drone/push Build is passing Details
2024-09-20 11:32:48 +07:00
irfan 3de7bfbbe5 Merge pull request 'fix/price-calculator' (#94) from fix/price-calculator into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #94
2024-09-20 04:07:24 +00:00
shancheas 60c03fefa0 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/price-calculator
continuous-integration/drone/push Build is passing Details
2024-09-20 11:06:31 +07:00
shancheas b34d54e7d0 fix: item bundling replace when edit 2024-09-20 11:06:09 +07:00
Firman Ramdhani 3fd97b8879 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-20 09:46:25 +07:00
irfan 93c822f34e Merge pull request 'fix/price-calculator' (#93) from fix/price-calculator into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #93
2024-09-19 12:34:03 +00:00
shancheas e09c76309e fix: formula calculation
continuous-integration/drone/push Build is passing Details
2024-09-19 19:33:28 +07:00
Firman Ramdhani 43deb04d92 feat(SPG-966): fix report income
continuous-integration/drone/push Build is passing Details
2024-09-19 18:22:19 +07:00
shancheas 23043fb7f9 feat: change logic to save formula 2024-09-19 17:52:50 +07:00
Firman Ramdhani 1d377b574c feat(SPG-966): fix report income
continuous-integration/drone/push Build is passing Details
2024-09-19 17:50:11 +07:00
Firman Ramdhani 7d9f619858 feat(SPG-966): fix report income 2024-09-19 17:49:35 +07:00
shancheas c06a2a0a2b Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/price-calculator 2024-09-19 14:07:37 +07:00
shancheas cc71814648 fix: bulk transaction action
continuous-integration/drone/push Build is passing Details
2024-09-18 17:25:07 +07:00
irfan 004dfc9de5 Merge pull request 'feat/adjustment-report' (#92) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #92
2024-09-18 10:14:59 +00:00
Firman Ramdhani 09d6dbaab2 feat: remove console on auth
continuous-integration/drone/push Build is passing Details
2024-09-18 16:30:23 +07:00
Firman Ramdhani c76594d767 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-18 16:25:39 +07:00
Firman Ramdhani f4cf5178b8 feat: change auth concept
continuous-integration/drone/push Build is passing Details
2024-09-18 16:25:29 +07:00
shancheas ffbbf6e140 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-18 13:55:57 +07:00
shancheas 614a9346fb feat: price calculator 2024-09-18 13:55:47 +07:00
irfan f7c49d27d5 Merge pull request 'fix/income-report' (#91) from fix/income-report into development
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #91
2024-09-13 10:39:52 +00:00
irfan 2ee96a617f fix: income item breakdown report
continuous-integration/drone/push Build was killed Details
2024-09-13 10:39:04 +00:00
irfan 10049abc55 fix: income item report
continuous-integration/drone/push Build is passing Details
2024-09-13 10:38:32 +00:00
irfan 01fbedab77 fix: income report
continuous-integration/drone/push Build is passing Details
2024-09-13 10:37:15 +00:00
irfan b2659def9a ci: rollback to yarn, NPM is s*ck
continuous-integration/drone/push Build is passing Details
2024-09-13 03:55:52 +00:00
firmanr d597734467 Merge pull request 'feat: exclude privilege logout' (#90) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #90
2024-09-13 03:49:40 +00:00
Firman Ramdhani 27a0c56af7 feat: exclude privilege logout
continuous-integration/drone/push Build is passing Details
2024-09-13 10:48:45 +07:00
irfan 50ac2d97a4 ci: update Docker file use NPM instead of Yarn
continuous-integration/drone/push Build is passing Details
2024-09-13 03:27:14 +00:00
firmanr d788a9f1a1 Merge pull request 'feat(SPG-953): penyesuaian API Create dan Update pengguna baru dengan menambahkan opsi admin antrian' (#89) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #89
2024-09-12 12:19:09 +00:00
Firman Ramdhani c897e4fcde feat(SPG-885): add validation login admin queue
continuous-integration/drone/push Build is passing Details
2024-09-12 19:17:46 +07:00
Firman Ramdhani 14dd2880bc feat(SPG-885): add api get item queue
continuous-integration/drone/push Build is passing Details
2024-09-12 17:54:48 +07:00
Firman Ramdhani 3e920755bd feat: create feature log user login and create auth admin queue
continuous-integration/drone/push Build is passing Details
2024-09-12 17:16:56 +07:00
Firman Ramdhani 88b4c66139 feat: adjustment column dpp and total pajak at income item master
continuous-integration/drone/push Build is passing Details
2024-09-11 18:15:16 +07:00
Firman Ramdhani 52c82a9a41 feat(SPG-953): penyesuaian API Create dan Update pengguna baru dengan menambahkan opsi admin antrian
continuous-integration/drone/push Build is passing Details
2024-09-11 16:43:03 +07:00
shancheas 19494b3328 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-09-11 16:12:36 +07:00
shancheas e1f2cdfa4d wip: calculate share item 2024-09-11 16:12:22 +07:00
firmanr 918055beb9 Merge pull request 'feat: add enum queue admin' (#88) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #88
2024-09-11 07:57:35 +00:00
Firman Ramdhani 283b783007 feat: add enum queue admin
continuous-integration/drone/push Build is passing Details
2024-09-11 14:56:55 +07:00
firmanr a2be2bb331 Merge pull request 'feat/adjustment-report' (#87) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #87
2024-09-11 05:44:29 +00:00
Firman Ramdhani d708ef9eee feat: add column pos name
continuous-integration/drone/push Build is passing Details
2024-09-11 12:42:09 +07:00
Firman Ramdhani 9709c4719b feat: add column pos name
continuous-integration/drone/push Build is passing Details
2024-09-11 12:38:16 +07:00
firmanr d2db62339f Merge pull request 'feat: penyesuaian error validasi create items' (#86) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #86
2024-09-11 04:05:56 +00:00
Firman Ramdhani 07d1cc78e2 feat: penyesuaian error validasi create items
continuous-integration/drone/push Build is passing Details
2024-09-11 11:05:36 +07:00
firmanr 8f430574ed Merge pull request 'feat: rename label button email template midtrans' (#85) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #85
2024-09-11 03:58:36 +00:00
Firman Ramdhani f7198010d3 feat: rename label button email template midtrans
continuous-integration/drone/push Build is passing Details
2024-09-11 10:57:25 +07:00
firmanr a1641504f1 Merge pull request 'feat/adjustment-report' (#84) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #84
2024-09-11 03:52:02 +00:00
Firman Ramdhani 6c5019f814 feat: adjustment dpp and total pajak di report icom per transaction
continuous-integration/drone/push Build is passing Details
2024-09-11 10:51:10 +07:00
Firman Ramdhani ff0ef28783 feat: create report tenant
continuous-integration/drone/push Build is passing Details
2024-09-11 10:40:44 +07:00
firmanr 40aafaf571 Merge pull request 'feat: ignore sync delete data from POS data' (#83) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #83
2024-09-10 10:26:19 +00:00
Firman Ramdhani 6fbb2e33b2 feat: ignore sync delete data from POS data
continuous-integration/drone/push Build is passing Details
2024-09-10 17:25:59 +07:00
firmanr b20385dacc Merge pull request 'feat/adjustment-report' (#82) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #82
2024-09-10 10:17:42 +00:00
Firman Ramdhani 6e5b19380b feat(SPG-935): add column payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-10 17:15:52 +07:00
Firman Ramdhani ab9ec4ac0e feat(SPG-935): add column payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-10 17:11:20 +07:00
firmanr 0457fc9e1d Merge pull request 'feat/adjustment-report' (#81) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #81
2024-09-10 04:49:35 +00:00
Firman Ramdhani 3658ae4cdf feat: adjustment filter pos no
continuous-integration/drone/push Build is passing Details
2024-09-10 11:48:44 +07:00
Firman Ramdhani d1b20e6b96 feat: create report tenant
continuous-integration/drone/push Build is passing Details
2024-09-10 11:38:46 +07:00
Firman Ramdhani f4ecbf0e66 feat: add net pedapatan di report rekonsiliasi
continuous-integration/drone/push Build is passing Details
2024-09-10 10:55:13 +07:00
Firman Ramdhani 7da22277f1 feat: remove MDR column on income
continuous-integration/drone/push Build is passing Details
2024-09-10 10:37:48 +07:00
Firman Ramdhani bf73cb6b43 feat: adjustment to measure at column income report
continuous-integration/drone/push Build is passing Details
2024-09-10 10:29:31 +07:00
Firman Ramdhani 6fb582204a Merge branch 'feat/fix-couch-transaction' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-09 14:30:53 +07:00
Firman Ramdhani d283caa898 feat: rename label header
continuous-integration/drone/push Build is passing Details
2024-09-09 14:26:49 +07:00
Firman Ramdhani 1320492bf1 Merge branch 'production' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-09 11:26:48 +07:00
firmanr 4c25b2cbec Merge pull request 'feat: open guard cancel recap recon and add new logic for recap recon cancel handler and change logic recap handler' (#79) from feat/reconciliation into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build encountered an error Details
Reviewed-on: #79
2024-09-06 11:42:28 +00:00
irfan a6b1e5f49f Update Dockerfile
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-06 11:05:32 +00:00
firmanr ac3ee266b9 Merge pull request 'feat: open guard cancel recap recon and add new logic for recap recon cancel handler and change logic recap handler' (#80) from feat/reconciliation into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #80
2024-09-06 10:58:46 +00:00
Firman Ramdhani 3720df31d8 feat: open guard cancel recap recon and add new logic for recap recon cancel handler and change logic recap handler
continuous-integration/drone/push Build is passing Details
2024-09-06 17:57:51 +07:00
Firman Ramdhani 7fb2995f38 feat: update query report income and merge with development branch
continuous-integration/drone/push Build is passing Details
2024-09-04 18:26:40 +07:00
Firman Ramdhani 07e7b86cd4 feat: update query report income and merge with development branch
continuous-integration/drone/push Build is passing Details
2024-09-04 18:21:08 +07:00
Firman Ramdhani db57b1973e Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/fix-couch-transaction 2024-09-04 18:20:13 +07:00
Firman Ramdhani 92d60d4496 feat: update query report income
continuous-integration/drone/push Build is passing Details
2024-09-04 18:19:42 +07:00
firmanr b716c75a2c Merge pull request 'feat/fix-couch-transaction' (#78) from feat/fix-couch-transaction into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #78
2024-09-04 10:26:33 +00:00
Firman Ramdhani 45306dde57 feat: update import couch module
continuous-integration/drone/push Build is passing Details
2024-09-04 15:22:42 +07:00
irfan 539676aa30 chore: add label to apm
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details
2024-09-03 11:45:30 +00:00
shancheas 1a2a37d185 chore: add label to APM 2024-09-03 18:44:04 +07:00
irfan 5666c31dfa Merge pull request 'pre-production' (#77) from pre-production into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #77
2024-09-03 11:16:58 +00:00
shancheas 665eacd39f feat: add reject QR gate
continuous-integration/drone/tag Build is passing Details
2024-09-03 10:23:02 +07:00
shancheas 9d98003a2d feat: add detail formula api getter
continuous-integration/drone/tag Build is passing Details
2024-09-03 09:45:23 +07:00
shancheas 45c4bde838 feat: add gate scanner module
continuous-integration/drone/tag Build is passing Details
2024-09-02 13:59:19 +07:00
shancheas b9927da0c4 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-09-02 13:07:38 +07:00
Firman Ramdhani d523009acd feat: add report income per item master
continuous-integration/drone/tag Build is failing Details
2024-08-30 19:32:03 +07:00
Firman Ramdhani 457ce30cc1 feat: update email template
continuous-integration/drone/tag Build is passing Details
2024-08-30 15:27:24 +07:00
shancheas e7a7ffb2bc feat: add variable config to formula 2024-08-29 17:19:24 +07:00
Firman Ramdhani 2527437577 feat: update validation unique data on payment method module
continuous-integration/drone/tag Build is passing Details
2024-08-29 13:31:24 +07:00
shancheas ce372de1fd fix: remove event when update privilege
continuous-integration/drone/tag Build is passing Details
2024-08-28 19:48:08 +07:00
firmanr 7e7d40ea1a Merge pull request 'feat/superset' (#76) from feat/superset into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #76
2024-08-27 02:53:05 +00:00
Firman Ramdhani 8590165755 feat: setup superset BE 2024-08-27 09:50:54 +07:00
Firman Ramdhani cb9421622d feat: setup env for superset BE 2024-08-27 09:44:49 +07:00
Firman Ramdhani dc97d5e14a feat: setup superset BE 2024-08-27 09:37:38 +07:00
firmanr 79adf156db Merge pull request 'feat: setup superset BE' (#75) from feat/superset into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #75
2024-08-26 12:04:40 +00:00
Firman Ramdhani 9f50d56cea feat: setup superset BE 2024-08-26 19:04:06 +07:00
Supan Adit Pratama 4a13730231 ci: fix production env
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-08-23 10:06:24 +07:00
shancheas c3950c7041 fix: update demography enum 2024-08-21 20:34:07 +07:00
shancheas 464c10722c fix: update item to update item rate 2024-08-21 18:42:53 +07:00
shancheas 9815c667f0 feat: create api to bulk update privileges
continuous-integration/drone/tag Build is passing Details
2024-08-21 17:06:20 +07:00
shancheas 84b829a7fa feat: add breakdown bundling to item transaction
continuous-integration/drone/tag Build is passing Details
2024-08-21 16:46:36 +07:00
shancheas eaf0f43a24 fix: add bundling to booking couch db
continuous-integration/drone/tag Build is passing Details
2024-08-21 11:14:41 +07:00
shancheas 22b418b257 fix: update price bundling items 2024-08-21 10:56:57 +07:00
shancheas d5adc48d9b fix: breakdown item rates wrong value
continuous-integration/drone/tag Build is passing Details
2024-08-21 10:30:05 +07:00
shancheas 009576c841 feat: add bundling relation for couch db
continuous-integration/drone/tag Build is passing Details
2024-08-20 18:37:10 +07:00
shancheas 7c7b121b49 fix: fix break down bundling item rates
continuous-integration/drone/tag Build is passing Details
2024-08-20 17:16:14 +07:00
shancheas 8abdbb7b55 fix: add mix nationality to demography 2024-08-20 15:44:32 +07:00
shancheas fc15cb9db6 fix: update transaction
continuous-integration/drone/tag Build is passing Details
2024-08-20 13:22:04 +07:00
shancheas 9a72c40984 feat: add bundling item to refund
continuous-integration/drone/tag Build is passing Details
2024-08-20 12:05:36 +07:00
shancheas f2bc4dd46d feat: add breakdown item to transaction 2024-08-20 11:52:20 +07:00
shancheas f4387767a8 fix: add item rate to bundling breakdown
continuous-integration/drone/tag Build is passing Details
2024-08-16 18:46:10 +07:00
shancheas 8b82f9b7db feat: estimation play to item 2024-08-16 16:44:04 +07:00
shancheas ee232447b6 fix: add breakdown bundling response to item and item rate
continuous-integration/drone/tag Build is passing Details
2024-08-16 15:11:15 +07:00
shancheas a2a9c16619 wip: add transaction demography model 2024-08-16 14:21:36 +07:00
shancheas 6227555671 wip: demography data 2024-08-15 17:12:35 +07:00
shancheas fa286820fc fix: add breakdown bundling and profit to response
continuous-integration/drone/tag Build is passing Details
2024-08-15 17:12:12 +07:00
shancheas e966de6158 feat: add bundling breakdown type 2024-08-15 16:04:15 +07:00
shancheas 50e8951b71 feat: add share profit to item
continuous-integration/drone/tag Build is passing Details
2024-08-15 14:27:54 +07:00
firmanr cefeef8854 Merge pull request 'feat: fixed midtrans' (#73) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #73
2024-08-12 13:01:13 +00:00
Firman Ramdhani f30a23d3c4 feat: fixed midtrans 2024-08-12 20:00:47 +07:00
shancheas dcf0a55dfc fix: remove payment_type_method_id when cancel
continuous-integration/drone/tag Build was killed Details
2024-08-12 19:59:57 +07:00
firmanr 3678353f34 Merge pull request 'feat: fixed midtrans' (#72) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #72
2024-08-12 12:51:36 +00:00
Firman Ramdhani ab903d4554 feat: fixed midtrans 2024-08-12 19:51:17 +07:00
shancheas bd13f50bc0 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-12 19:47:21 +07:00
shancheas f4939ffe89 fix: cancel data payment 2024-08-12 19:47:10 +07:00
firmanr 4fe385bca1 Merge pull request 'feat: fixed midtrans' (#71) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #71
2024-08-12 12:41:38 +00:00
Firman Ramdhani be7c74ec72 feat: fixed midtrans 2024-08-12 19:40:54 +07:00
shancheas 88cc9f4bc3 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-12 19:34:54 +07:00
shancheas dc595dfb07 fix: mapping transaction cancel 2024-08-12 19:34:34 +07:00
firmanr 211a1e8a3c Merge pull request 'feat: fixed midtrans' (#70) from fix/bug-firman into development
Reviewed-on: #70
2024-08-12 12:30:39 +00:00
Firman Ramdhani 08e018e16b Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/bug-firman 2024-08-12 19:30:20 +07:00
Firman Ramdhani cc62910493 feat: fixed midtrans 2024-08-12 19:29:21 +07:00
firmanr ff44be66e2 Merge pull request 'feat: fixed midtrans' (#69) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #69
2024-08-12 12:27:03 +00:00
Firman Ramdhani b9b1695dc5 feat: fixed midtrans 2024-08-12 19:26:39 +07:00
firmanr 617a08e3f2 Merge pull request 'feat: fixed midtrans' (#68) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #68
2024-08-12 12:14:51 +00:00
Firman Ramdhani aaf6f97e57 feat: fixed midtrans 2024-08-12 19:14:25 +07:00
shancheas 538bd0e58e Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-12 18:41:45 +07:00
shancheas ceae06779e fix: booking date undefined 2024-08-12 18:41:28 +07:00
firmanr 5e78669b6c Merge pull request 'feat: fixed midtrans' (#67) from fix/bug-firman into development
continuous-integration/drone/tag Build was killed Details
Reviewed-on: #67
2024-08-12 11:40:21 +00:00
Firman Ramdhani a015353990 feat: fixed midtrans 2024-08-12 18:37:37 +07:00
firmanr 01b4ee2bbd Merge pull request 'feat(SPG-851): fix midtrans' (#66) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #66
2024-08-12 11:02:49 +00:00
Firman Ramdhani c65f0dc9dc feat(SPG-851): fix midtrans 2024-08-12 18:01:59 +07:00
firmanr c98b8da9ba Merge pull request 'feat:' (#65) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #65
2024-08-12 09:18:08 +00:00
Firman Ramdhani bca3682826 feat: 2024-08-12 16:17:36 +07:00
irfan 11aeb44bac Update .drone.yml 2024-08-12 09:04:29 +00:00
irfan 07347c9244 Update .drone.yml 2024-08-12 09:03:32 +00:00
shancheas 29cc6dfae6 fix: add parameter payment total value greater than 0
continuous-integration/drone/tag Build is passing Details
2024-08-12 15:54:21 +07:00
shancheas f9937d84ab fix(SPG-848): exclude counter transaction with null payment type 2024-08-12 15:46:53 +07:00
shancheas a14119719c ci: change mattermost token 2024-08-12 13:56:45 +07:00
shancheas ae75578b65 ci: remove timeout
continuous-integration/drone/tag Build is passing Details
2024-08-12 13:45:56 +07:00
shancheas 93fa32df80 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is failing Details
2024-08-12 13:42:03 +07:00
shancheas f7d7fba267 ci: change pipeline formula 2024-08-12 13:41:43 +07:00
firmanr ebcc5515e5 Merge pull request 'fix/bug-firman' (#64) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #64
2024-08-12 03:52:05 +00:00
Firman Ramdhani b597a2f184 feat(SPG-265): report reconciliation 2024-08-12 10:50:02 +07:00
Firman Ramdhani 7a6c784612 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/bug-firman 2024-08-09 17:38:47 +07:00
Firman Ramdhani d6fc817cef feat: remove unused report 2024-08-09 17:38:35 +07:00
firmanr 89aa2a68b4 Merge pull request 'fix/bug-firman' (#63) from fix/bug-firman into development
Reviewed-on: #63
2024-08-09 10:23:54 +00:00
Firman Ramdhani 64d812bef1 feat(SPG-267): report cash withdrawals 2024-08-09 17:21:12 +07:00
Firman Ramdhani 3b8310581b feat(SPG-266): report cashier log 2024-08-09 16:10:57 +07:00
Firman Ramdhani 21b9549b52 feat(SPG-264): report refund 2024-08-09 16:06:17 +07:00
Firman Ramdhani 76b518614f feat(SPG-263): report pemesanan 2024-08-09 15:52:53 +07:00
Firman Ramdhani 841f8889ec Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/bug-firman 2024-08-09 15:43:25 +07:00
Firman Ramdhani bc8476a56e feat(SPG-268): report pemberian diskon 2024-08-09 15:43:13 +07:00
shancheas fe6572a770 fix: only check transaction more than 1 day
continuous-integration/drone/tag Build is passing Details
2024-08-09 15:23:20 +07:00
shancheas acf8861823 feat: add sync midtrans transaction 2024-08-09 15:18:43 +07:00
Firman Ramdhani a319b64abe feat(SPG-259): report pendapatan per item 2024-08-09 15:14:37 +07:00
firmanr 3938504fd3 Merge pull request 'feat: fix access control download' (#62) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #62
2024-08-09 04:27:43 +00:00
Firman Ramdhani 3b07c8de99 feat: fix access control download 2024-08-09 11:27:00 +07:00
firmanr fc67c222f8 Merge pull request 'feat(SPG-258): create report income and fix calculate hpp on transaction' (#61) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #61
2024-08-09 04:18:33 +00:00
Firman Ramdhani f0c1410532 feat(SPG-258): create report income and fix calculate hpp on transaction 2024-08-09 11:16:56 +07:00
shancheas c5fdca615f fix(SPG-816): add payment date and payment method
continuous-integration/drone/tag Build is passing Details
2024-08-08 18:24:59 +07:00
shancheas e00a6aae31 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-08 18:10:32 +07:00
shancheas f5425ccfb1 feat: add change status midtrans 2024-08-08 18:10:18 +07:00
firmanr 995f4b963c Merge pull request 'fix/bug-firman' (#60) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #60
2024-08-08 10:29:37 +00:00
Firman Ramdhani 13895394b3 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/bug-firman 2024-08-08 17:28:42 +07:00
Firman Ramdhani b36e35ea00 feat(SPG-823): add item access control 2024-08-08 17:28:17 +07:00
shancheas e9c819987e fix: add payment_midtrans_url to transactions
continuous-integration/drone/tag Build was killed Details
2024-08-08 17:27:51 +07:00
shancheas a61f8b853d fix(SPG-817): invoice expired not send email
continuous-integration/drone/tag Build is passing Details
2024-08-08 17:07:03 +07:00
shancheas efe5661a57 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-08 15:47:53 +07:00
shancheas 30d3d91bba fix(SPG-817): send email when status expired 2024-08-08 15:47:39 +07:00
firmanr 1fa4d315be Merge pull request 'fix/bug-firman' (#59) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #59
2024-08-08 08:42:34 +00:00
shancheas bcdf656d5d fix: midtrans error total != qty * price 2024-08-08 15:34:34 +07:00
Firman Ramdhani 63152ec90e feat(SPG-833): add key refund_type on get index 2024-08-08 15:24:35 +07:00
Firman Ramdhani 990d73bdb1 feat(SPG-837): validate delete and in active when data session type has relation 2024-08-08 15:07:38 +07:00
Firman Ramdhani 1dae9ec356 feat(SPG-780): sync data session type 2024-08-08 14:51:38 +07:00
Firman Ramdhani 8de744bc58 feat(SPG-782): update base price at item rate when price on item rate not edited before 2024-08-08 13:19:03 +07:00
Firman Ramdhani f8618ec0cd Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/bug-firman 2024-08-08 11:28:54 +07:00
shancheas 1e8a07ec55 fix: change pos transaction event from update to change status 2024-08-08 11:27:20 +07:00
Firman Ramdhani 810a1c5bf5 feat: add planning comment for handle change status from multiple tabs 2024-08-07 22:18:19 +07:00
firmanr 1d8a3d7ff9 Merge pull request 'feat(SPG-818): fix condition transaction status change handler' (#58) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #58
2024-08-07 11:47:44 +00:00
Firman Ramdhani b57da1d21a feat(SPG-818): fix condition transaction status change handler 2024-08-07 18:47:08 +07:00
shancheas 8dd36042eb fix(SPG-804): cancel transaction to pending booking
continuous-integration/drone/tag Build is passing Details
2024-08-07 18:04:53 +07:00
firmanr 72e47c2486 Merge pull request 'feat(SPG-737): fix filter reconciliation' (#57) from fix/bug-firman into development
Reviewed-on: #57
2024-08-07 10:46:32 +00:00
Firman Ramdhani cfb0d3c60f feat(SPG-792) : fix sync transaction data 2024-08-07 17:46:14 +07:00
Firman Ramdhani 0c3abc6a8f feat: add get data on couch service 2024-08-07 16:41:13 +07:00
Firman Ramdhani 1fcbe57018 feat: remove console 2024-08-07 16:33:20 +07:00
Firman Ramdhani ba6ee4a408 feat(SPG-737): fix filter reconciliation 2024-08-07 14:47:19 +07:00
shancheas e4a631b929 fix: move google credential to folder
continuous-integration/drone/tag Build is passing Details
2024-08-07 12:30:55 +07:00
shancheas dbdc7a0203 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-08-07 11:48:55 +07:00
shancheas fcaf4a07a1 log: add APM to handler 2024-08-07 11:48:39 +07:00
firmanr 9efa56b2bc Merge pull request 'feat(SPG-800): add validation delete on data booking transaction' (#56) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #56
2024-08-07 04:32:44 +00:00
Firman Ramdhani 0658b503bd feat(SPG-656): allow input number on formula 2024-08-07 11:05:37 +07:00
Firman Ramdhani 9802d983bb feat(SPG-800): add validation delete on data booking transaction 2024-08-07 10:31:19 +07:00
firmanr 583b754315 Merge pull request 'Update env/env.production' (#55) from fix/bug-firman into development
Reviewed-on: #55
2024-08-06 10:40:09 +00:00
Firman Ramdhani 4ef139b2f5 Update env/env.production 2024-08-06 17:39:53 +07:00
irfan b137e1abce Update env/env.development
continuous-integration/drone/tag Build is passing Details
2024-08-06 10:38:18 +00:00
shancheas e8baaa12d2 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-08-06 16:06:43 +07:00
shancheas 6ca74ad6f7 fix: lint 2024-08-06 16:06:30 +07:00
firmanr 955f00cc9d Merge pull request 'feat(SPG-793): fix time at report log' (#54) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #54
2024-08-06 09:05:27 +00:00
Firman Ramdhani b48a469720 feat(SPG-772): fix key settlement date on booking module 2024-08-06 16:04:20 +07:00
shancheas 61d8f56385 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build was killed Details
2024-08-06 16:04:13 +07:00
shancheas 2a42d85814 chore: add vscode debug configuration 2024-08-06 16:03:55 +07:00
shancheas bacdb1773b fix: item rates not generated when create period season 2024-08-06 16:03:42 +07:00
Firman Ramdhani 655157239d feat(SPG-793): fix time at report log 2024-08-06 13:23:21 +07:00
firmanr 33014394d1 Merge pull request 'feat(SPG-773): set item name to unique' (#53) from fix/bug-firman into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #53
2024-08-06 05:48:50 +00:00
Firman Ramdhani aaee458df6 feat(SPG-773): set item name to unique 2024-08-06 12:47:09 +07:00
firmanr ffcbf65d9d Merge pull request 'feat/report' (#52) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #52
2024-08-06 05:35:06 +00:00
Firman Ramdhani 2f19db8dd7 feat(SPG-777): add validation delete for tenant item bundling 2024-08-06 11:40:18 +07:00
Firman Ramdhani e7664be8a8 feat(SPG-777): add validation delete for tenant item bundling 2024-08-06 11:39:40 +07:00
Firman Ramdhani a2c1af2a65 merge 2024-08-06 11:38:17 +07:00
Firman Ramdhani 26db7d2745 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-08-06 11:37:59 +07:00
Firman Ramdhani e922db827d feat(SPG-777): add validation delete for tenant item bundling 2024-08-06 11:33:51 +07:00
shancheas 5dde995ab8 fix: fail to cancel transaction
continuous-integration/drone/tag Build is passing Details
2024-08-06 10:37:56 +07:00
shancheas 79d1c564ff log: add APM log to couch handler
continuous-integration/drone/tag Build is passing Details
2024-08-06 06:16:10 +07:00
shancheas e7abc7db13 fix: move mail template to assets folder 2024-08-06 06:13:13 +07:00
shancheas 81a463e761 chore: update file location
continuous-integration/drone/tag Build is passing Details
2024-08-05 15:37:27 +07:00
shancheas c741a55577 fix: move image from file to base64 string
continuous-integration/drone/tag Build is passing Details
2024-08-05 15:18:24 +07:00
shancheas 81dad9a69c fix: change logo image location
continuous-integration/drone/tag Build is passing Details
2024-08-05 15:00:13 +07:00
shancheas 8999ed1bf0 fix: error image and typo
continuous-integration/drone/tag Build is passing Details
2024-08-05 14:43:42 +07:00
aswin ebfcbb85fe Merge pull request 'feat/pdf-generator' (#51) from feat/pdf-generator into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #51
2024-08-03 19:52:58 +00:00
Aswin Ashar Abdullah feee9a3439 fix(SPG-494) PDF Generator 2024-08-04 02:51:11 +07:00
aswin b05e6fab5a Merge pull request 'development' (#50) from development into feat/pdf-generator
Reviewed-on: #50
2024-08-02 12:01:09 +00:00
aswin 37350e454f Merge pull request 'fix/data' (#49) from fix/data into development
Reviewed-on: #49
2024-08-02 12:00:23 +00:00
Aswin Ashar Abdullah b08325a53c fix(email) checkpoint email service 2024-08-02 18:59:31 +07:00
Aswin Ashar Abdullah a1f7108bc5 feat(SPG-233) Integration Google Calendar API 2024-08-02 18:36:42 +07:00
Aswin Ashar Abdullah 2e4d5df17a fix(SPG-762) BE - integrasi dengan API Midtrans - untuk update status pembayaran 2024-08-02 18:11:36 +07:00
Aswin Ashar Abdullah 4fcd852d8d fix(SPG-769) save edit data terkena validasi status transaksi settled 2024-08-02 17:59:30 +07:00
Aswin Ashar Abdullah 0f05656ca2 fix(booking) perbaikan column payment type counter 2024-08-02 17:54:12 +07:00
Aswin Ashar Abdullah 0bec3c6590 fix(SPG-750) Ketika sales di PoS di cancel, pada rekondiliasi - recap, valuenya tidak berkurang 2024-08-02 17:53:29 +07:00
Aswin Ashar Abdullah 8eee99fce5 fix(SPG-745) Data booking status active dan settled (tipe pembayaran selain counter) belum masuk PoS 2024-08-02 17:49:11 +07:00
Aswin Ashar Abdullah 239e2d778a feat(SPG-760) Validasi Bundling dan Item active inactive 2024-08-02 17:12:12 +07:00
Aswin Ashar Abdullah cc01b23e2a fix(SPG-754) Di hak akses PoS, penjualan seharusnya tidak ada check box delete 2024-08-02 16:56:34 +07:00
Aswin Ashar Abdullah 0b502188af fix(SPG-687) Booking status pending seharusnya bisa di cancel 2024-08-02 16:08:26 +07:00
Aswin Ashar Abdullah e38fbc65bd fix(SPG-759) Ketika ada item baru dibuat ( kondisi sudah ada data item rate untuk product lain ) 2024-08-02 16:00:05 +07:00
Aswin Ashar Abdullah 0e47b99ca7 fix(SPG-756) Untuk value field sales margin (%) seharusnya bisa mempunyai value dibelakang koma 2024-08-02 15:28:56 +07:00
Aswin Ashar Abdullah e401a1bf4c fix(SPG-742) Filter status, sumber, tipe pembayaran, pembayaran via, bank, tgl konfirmasi belum jalan 2024-08-02 15:16:43 +07:00
Aswin Ashar Abdullah 1636f6b930 fix(SPG-743) Refund dengan code invoice yang sama terkena validasi 2024-08-02 14:38:36 +07:00
aswin d1892e7aa5 Merge pull request 'development' (#48) from development into feat/pdf-generator
Reviewed-on: #48
2024-08-02 06:32:20 +00:00
Firman Ramdhani d14d9101ae feat: add report CashierLogReport and CashWithdrawalsReport
continuous-integration/drone/tag Build is passing Details
2024-08-01 18:09:40 +07:00
Firman Ramdhani 746e24feb6 feat: add migration for table pos log
continuous-integration/drone/tag Build is passing Details
2024-08-01 17:48:21 +07:00
Firman Ramdhani 39d7eb28b9 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-08-01 17:45:55 +07:00
Firman Ramdhani 9d0d76120e feat: update model pos log 2024-08-01 17:45:33 +07:00
aswin 971407612c Merge pull request 'fix/data' (#47) from fix/data into development
Reviewed-on: #47
2024-08-01 10:37:35 +00:00
Aswin Ashar Abdullah 03ec533e86 fix(SPG-736) Cancel rekon statu Pending terkena validasi data pemesanan harus settled 2024-08-01 17:33:36 +07:00
Aswin Ashar Abdullah d413bd771b fix(SPG-735) Ketika recap di click berkali kali, transaksi menggunakan tipe cash jadi duplicate 2024-08-01 17:25:12 +07:00
Aswin Ashar Abdullah 11171b2859 fix(SPG-729) pemesanan data seharusnya berstatus proses refund ketika data refund berstatus draft 2024-08-01 17:01:39 +07:00
Firman Ramdhani 1e9cc9da4f feat: add default condition for type on booking report 2024-08-01 15:13:00 +07:00
Firman Ramdhani 46307774e1 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-08-01 14:43:43 +07:00
Firman Ramdhani 62eccf29a5 feat: rename header title report 2024-08-01 14:43:37 +07:00
Aswin Ashar Abdullah 383fdce9f7 feat(pdf) checkpoint pdf 2024-08-01 14:36:20 +07:00
Aswin Ashar Abdullah 1ae7f4e097 fix(booking) perbaikan event deleted booking 2024-08-01 14:27:57 +07:00
aswin 33f955c209 Merge pull request 'fix/data' (#46) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #46
2024-08-01 07:01:41 +00:00
Aswin Ashar Abdullah d4bd3d746c fix(filter) perbaikan filter season period 2024-08-01 14:00:14 +07:00
Aswin Ashar Abdullah 45f11003f2 fix(privilege) perbaikan privilege constants 2024-08-01 13:33:02 +07:00
Aswin Ashar Abdullah 2188d63943 fix(SPG-726) Update image pada item status active, data image tidak ter sync ke PoS 2024-07-31 19:05:08 +07:00
Aswin Ashar Abdullah 3af56fa5d5 fix(SPG-652) Item Tipe Bundling - validasi 2024-07-31 18:51:31 +07:00
aswin 77d8e7ae1e Merge pull request 'fix/data' (#45) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #45
2024-07-31 11:27:39 +00:00
Aswin Ashar Abdullah c49bb379bd fix(item price) perbaikan price item 2024-07-31 18:25:28 +07:00
Aswin Ashar Abdullah 0648eeffee fix(SPG-711) Internal server error sering sekali ketika confirm status draft ke status pending 2024-07-31 18:24:47 +07:00
Aswin Ashar Abdullah e8deba2882 fix(SPG-709) Data summary transaksi PoS tidak muncul di halaman rekonsiliasi setelah click button recap 2024-07-31 17:58:33 +07:00
Aswin Ashar Abdullah 19386c336e fix(SPG-710) ganti warning cancel jadi bahasa indonesia 2024-07-31 17:58:01 +07:00
Aswin Ashar Abdullah 58cf3f7ab0 fix(SPG-718) Validasi perubahan tipe wahana seharusnya tidak memvalidasi perubahan namanya 2024-07-31 16:29:04 +07:00
Aswin Ashar Abdullah d7c4b27749 feat(SPG-719) Season Period - API Index - tambahkan filter berdasarkan season type 2024-07-31 16:19:30 +07:00
Aswin Ashar Abdullah 0ac5754170 fix(SPG-703) Sync account superadmin ke Pouch Couch supaya bisa login di PoS 2024-07-31 16:11:59 +07:00
Aswin Ashar Abdullah b7557a5f19 fix(SPG-663) Pos Privileges - pemesanan seharusnya tidak ada create 2024-07-31 15:53:41 +07:00
aswin 1590080468 Merge pull request 'fix(transaction) perbaikan data' (#44) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #44
2024-07-30 12:26:06 +00:00
Aswin Ashar Abdullah 61c512f7f4 fix(transaction) perbaikan data 2024-07-30 19:25:22 +07:00
aswin 30ffdca550 Merge pull request 'fix/data' (#43) from fix/data into development
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #43
2024-07-30 11:33:11 +00:00
Aswin Ashar Abdullah c154af6cb7 fix(SPG-708) Muncul error saat meng cancel status pending - warninnya hanya bisa meng cancel status pending juga 2024-07-30 18:26:50 +07:00
Aswin Ashar Abdullah 197b3478ae fix(SPG_693) di hak akses pos pada bagian penjualan seharusnya ada checkbox pada kolom cancel dan ada hak akses reprint receipt 2024-07-30 18:22:23 +07:00
Aswin Ashar Abdullah c6be42299e fix(SPG-697) Pada index booking seharusnya transaksi pos tidak muncul, dan sesuaikan alur booking dengan pembayaran counter 2024-07-30 17:12:55 +07:00
Firman Ramdhani 9bcc72a69e feat: fix set false bookmark report
continuous-integration/drone/tag Build is passing Details
2024-07-30 16:59:11 +07:00
Aswin Ashar Abdullah dc6476a66f fix(SPG-687) Booking status pending seharusnya bisa di cancel, tapi ketika di cancel muncul error message, hanya status active yang bisa di cancel 2024-07-30 14:44:12 +07:00
Aswin Ashar Abdullah 4a9ca5eb5b fix(SPG-688) Ketika tgl booking di rubah web admin, tanggal booking pada PoS tidak ikut terupdate 2024-07-30 14:36:49 +07:00
aswin e1004b3843 Merge pull request 'fix/data' (#42) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #42
2024-07-30 06:56:07 +00:00
Aswin Ashar Abdullah 6632222c4b fix(SPG-677) Pada Index tgl invoice belum ada datanya, invoice data = tgl ketika booking di confirm ke status pending 2024-07-30 13:54:00 +07:00
Aswin Ashar Abdullah 945edbf76d fix(SPG-659) Muncul error get data saat confirm transaksi status draft ke pending 2024-07-30 13:50:23 +07:00
Aswin Ashar Abdullah 190f42d598 fix(SPG-645) Button generate price belum berfungsi 2024-07-30 13:46:57 +07:00
Aswin Ashar Abdullah d9bbe1290d fix(SPG-675) Error saat confirm status pending ( hanya bisa refund status settled ) padahal status sudah berubah ke proces refund 2024-07-30 13:08:50 +07:00
Aswin Ashar Abdullah 3e85d40885 feat(SPG-651) BE Reason Refund Request 2024-07-30 13:00:49 +07:00
Aswin Ashar Abdullah 7e38a67e80 fix(SPG-667) Kategori item status inactive seharusnya tidak terpanggil 2024-07-30 12:44:57 +07:00
Aswin Ashar Abdullah b91d9f7da8 fix(SPG-671) Item Bundling - validasi / warning jika item dalam bundling diinactivekan sedangkan masih berelasi, bundling harus di inactivekan dulu atau didelete 2024-07-30 12:24:31 +07:00
irfan bf8987242b Merge pull request 'fix: change query runner to repository from base manager' (#41) from fix/base-query into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #41
2024-07-29 09:47:00 +00:00
shancheas 57f2700c94 fix: change query runner to repository from base manager 2024-07-29 16:44:23 +07:00
Aswin Ashar Abdullah b3f0752ca0 fix(SPG-662) Search title banner belum jalan 2024-07-29 14:53:22 +07:00
Aswin Ashar Abdullah 33438f37ec fix(SPG-669) Validasi perubahan tipe wahana jika sudah mempunyai item yang berelasi 2024-07-29 14:48:05 +07:00
Aswin Ashar Abdullah 593955574a fix(SPG-664) admin Privilles - rekonsiliasi seharusnya tidak ada create 2024-07-29 14:37:46 +07:00
Aswin Ashar Abdullah 4ac711add5 fix(SPG-663) Pos Privilleges - pemesanan seharusnya tidak ada create 2024-07-29 14:37:12 +07:00
aswin c7fa402663 Merge pull request 'fix/data' (#40) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #40
2024-07-26 10:20:47 +00:00
Aswin Ashar Abdullah 6096771597 fix(SPG-658) Validasi - tidak bisa confirm dari status pending ke waiting, ketika data pembayaran booking belum diisi ( untuk pembayaran bank transfer dan QRIS saja) 2024-07-26 17:14:04 +07:00
Aswin Ashar Abdullah 76fa380f1e fix(SPG-657) Kode Pembayaran - ketika booking status waiting di confirm di rekonsiliasi, kode pembayaran tidak muncul 2024-07-26 16:49:52 +07:00
Aswin Ashar Abdullah 1f4bf80908 fix(SPG-661) Filter rekonsiliasi exclude status draft 2024-07-26 16:28:25 +07:00
Aswin Ashar Abdullah 66c481c9b0 fix(SPG-645) Button generate price belum berfungsi 2024-07-26 16:20:22 +07:00
Aswin Ashar Abdullah 9cd50ad817 fix(SPG-655) Item Rate saat filter harga jadi mengambil base price (kemungkinan ada salah ambil priority 2024-07-26 15:43:34 +07:00
Aswin Ashar Abdullah 82105e8214 fix(rate) perbaikan update rate 2024-07-26 15:05:28 +07:00
Aswin Ashar Abdullah e68524380a fix(SPG-652) Item Tipe Bundling - Item yang sudah berrelasi atau dipakai pada bundling tidak dapat di delete atau di inactivekan sampai di lepas dari bundling nya 2024-07-26 15:03:37 +07:00
aswin d333ba03a7 Merge pull request 'fix(season) update fix priority' (#39) from fix/data into development
Reviewed-on: #39
2024-07-26 07:04:31 +00:00
Aswin Ashar Abdullah a63eaf0110 fix(season) update fix priority 2024-07-26 14:03:38 +07:00
Aswin Ashar Abdullah e32a7c2eaf fix(base) delete query transaction
continuous-integration/drone/tag Build is passing Details
2024-07-26 11:41:18 +07:00
aswin 07f379a6b0 Merge pull request 'fix/data' (#38) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #38
2024-07-26 03:06:59 +00:00
Aswin Ashar Abdullah 39896fed90 fix(env) update env value 2024-07-26 10:06:11 +07:00
Aswin Ashar Abdullah a671404947 feat(SPG-554) BE - Integrasi Booking dengan Google Calendar 2024-07-25 16:03:43 +07:00
aswin 00d5eba7ab Merge pull request 'fix/data' (#37) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #37
2024-07-23 12:58:11 +00:00
Aswin Ashar Abdullah d0163ae003 feat(SPG-125) Logging 2024-07-23 19:54:00 +07:00
Aswin Ashar Abdullah aa550f9d38 feat(SPG-612) Activity Log PoS 2024-07-23 19:24:40 +07:00
Aswin Ashar Abdullah 2fc80c7cfc fix(SPG-640) Sync harga ketika ditambahkan melalui item rate (case item sudah dibuat) 2024-07-23 18:25:57 +07:00
Aswin Ashar Abdullah 20848aab3c fix(SPG-644) Sync ketika privileges di update 2024-07-23 18:25:14 +07:00
aswin d81eaac4f6 Merge pull request 'fix/data' (#36) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #36
2024-07-22 11:34:52 +00:00
Aswin Ashar Abdullah 679b98d198 fix(SPG-611) Upload - pemindahan directory upload image 2024-07-22 18:33:50 +07:00
Aswin Ashar Abdullah 1ff5461311 fix(SPG-645) Button generate price belum berfungsi 2024-07-22 12:29:36 +07:00
Firman Ramdhani 2f9c96bdec Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-07-22 11:56:42 +07:00
Firman Ramdhani b1bc05fcb9 feat: adjustment report 2024-07-22 11:56:35 +07:00
Aswin Ashar Abdullah ef2697a3b1 fix(SPG-618) Error pada saat mengkonfirmasi / save pengembalian wahana baru 2024-07-22 11:40:43 +07:00
aswin 000c3f1800 Merge pull request 'fix/data' (#33) from fix/data into development
Reviewed-on: #33
2024-07-22 04:06:42 +00:00
Aswin Ashar Abdullah c5cec31ab5 fix(SPG-641) Validasi ketika process save untuk aksi di rekonsiliasi, save data di refund, dan aksi di booking 2024-07-20 22:12:09 +07:00
Aswin Ashar Abdullah cc92ef26a1 fix(index) perbaikan index item - item rates 2024-07-19 17:47:09 +07:00
Aswin Ashar Abdullah 1560cb0512 fix(SPG-643) Sync batch data couch pouch 2024-07-19 17:46:48 +07:00
Aswin Ashar Abdullah fba7b9aae5 fix(SPG-620) Sales Price & Profit Share Formula - Tambahkan warning/validasi jika formula menyebabkan error 2024-07-19 14:43:47 +07:00
Aswin Ashar Abdullah 0b236cb879 fix(SPG-619) Informasi Season Periode tidak muncul jika tgl dipilih bukan tanggal hari ini 2024-07-19 13:27:17 +07:00
aswin 41f4773df6 Merge pull request 'fix/data' (#32) from fix/data into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #32
2024-07-18 11:15:25 +00:00
Aswin Ashar Abdullah 908834cdd9 fix(item) perbaikan item price 2024-07-18 18:14:46 +07:00
Aswin Ashar Abdullah 4840abf18e fix(index) perbaikan index data sort by order 2024-07-18 15:36:56 +07:00
Aswin Ashar Abdullah cd6a5737e7 fix(SPG-600) Filter Sumber, Tipe, Kontak pada index booking belum berjalan 2024-07-18 15:36:38 +07:00
aswin 853543ece5 Merge pull request 'feat/midtrans' (#31) from feat/midtrans into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #31
2024-07-18 06:40:04 +00:00
Aswin Ashar Abdullah 37b12c960f fix(change-position) perbaikan change position module 2024-07-18 13:36:22 +07:00
Aswin Ashar Abdullah 8c9d0d6585 feat(SPG-423) Midtrans Integration 2024-07-18 12:45:46 +07:00
Aswin Ashar Abdullah 2551521539 feat(SPG-423) Midtrans Integration 2024-07-18 12:42:47 +07:00
Aswin Ashar Abdullah 403a75c835 feat(SPG-388) BE Send Mail with Google Mail 2024-07-17 19:10:35 +07:00
Firman Ramdhani 12359f3685 feat: setup colum report pengembalian
continuous-integration/drone/tag Build is passing Details
2024-07-17 14:18:59 +07:00
Firman Ramdhani d20fd4e175 feat: setup colum report pemesanan 2024-07-17 14:05:23 +07:00
aswin 05c98dcb14 Merge pull request 'feat/news' (#30) from feat/news into development
Reviewed-on: #30
2024-07-16 10:43:44 +00:00
firmanr d5bafe4f4f Merge pull request 'feat: fix get menu' (#29) from feat/privilege into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #29
2024-07-16 08:15:57 +00:00
Firman Ramdhani 6ca3766457 feat: fix get menu 2024-07-16 15:15:20 +07:00
Aswin Ashar Abdullah 9ac1fa9ae2 feat(SPG-460) REST API Read Banner 2024-07-16 13:30:33 +07:00
Aswin Ashar Abdullah 4178b72af9 feat(SPG-457) REST API CUD Banner 2024-07-16 13:30:17 +07:00
Aswin Ashar Abdullah bfa8d6d524 fix(filter) perbaikan filter search 2024-07-16 13:17:58 +07:00
Aswin Ashar Abdullah 7a74711834 feat(SPG-451) REST API Read berita 2024-07-16 13:17:41 +07:00
Aswin Ashar Abdullah 9056b60937 feat(SPG-448) REST API CUD Berita 2024-07-16 13:17:06 +07:00
Aswin Ashar Abdullah 75663c4f99 feat(SPG-521) Base Upload
continuous-integration/drone/tag Build is passing Details
2024-07-15 18:09:01 +07:00
Aswin Ashar Abdullah c2b5f27b3b fix(refund) perbaikan refund item 2024-07-15 18:08:44 +07:00
firmanr 84f7ed6d09 Merge pull request 'feat/privilege' (#28) from feat/privilege into development
continuous-integration/drone/tag Build was killed Details
Reviewed-on: #28
2024-07-15 11:07:31 +00:00
Firman Ramdhani eaa1e64899 feat: set exclude privilege on report api 2024-07-15 18:06:25 +07:00
Firman Ramdhani bad83aef69 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/privilege 2024-07-15 17:05:11 +07:00
Firman Ramdhani fc36997b91 feat: create api get privilege menu 2024-07-15 16:57:16 +07:00
Aswin Ashar Abdullah 7e18580540 fix(SPG-607) Transaksi booking dengan pembayaran tipe counter, tidak ada status waiting, dan tidak masuk ke rekonsiliasi
continuous-integration/drone/tag Build is passing Details
2024-07-15 16:49:54 +07:00
Aswin Ashar Abdullah e64799f7de fix(SPG-610) Membuat data season periode hari libur saja, ketika di save terbuat data season periode all juga 2024-07-15 16:40:45 +07:00
Aswin Ashar Abdullah 78ae2a5d8e fix(SPG-602) Harga Item belum mengambil harga season periode 2024-07-15 16:21:15 +07:00
Aswin Ashar Abdullah b574d3a39d fix(refund) perbaikan data refund
continuous-integration/drone/tag Build is passing Details
2024-07-15 15:24:02 +07:00
Aswin Ashar Abdullah eafd815463 feat(SPG-443) REST API Read FAQ 2024-07-15 15:17:36 +07:00
Aswin Ashar Abdullah 5a96282bce feat(SPG-440) REST API CUD FAQ 2024-07-15 15:17:01 +07:00
Aswin Ashar Abdullah 55d25644dd feat(SPG-437) REST API Read TnC 2024-07-15 15:12:47 +07:00
Aswin Ashar Abdullah 7a3d4b9432 feat(SPG-433) REST API CUD TnC 2024-07-15 15:02:17 +07:00
Aswin Ashar Abdullah af1a642907 feat(SPG-428) REST API Read Data Gate 2024-07-15 14:28:45 +07:00
Aswin Ashar Abdullah 0d2e49f93a feat(SPG-425) REST API CUD Data Gate 2024-07-15 14:28:25 +07:00
Aswin Ashar Abdullah 688be5828d fix(SPG-601) Confirm data status draft error - Cannot read properties of null (reading 'count')
continuous-integration/drone/tag Build is passing Details
2024-07-15 12:43:57 +07:00
Aswin Ashar Abdullah 001f371244 fix(SPG-600) Filter Sumber, Tipe, Kontak pada index booking belum berjalan 2024-07-15 12:43:17 +07:00
aswin 2a8d5e87cf Merge pull request 'feat/refund' (#27) from feat/refund into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #27
2024-07-12 10:52:01 +00:00
Aswin Ashar Abdullah 5c0886316c fix(format) perbaikan format and clean console log 2024-07-12 17:50:21 +07:00
Aswin Ashar Abdullah daf325b1a0 feat(SPG-393) REST API Read Refund 2024-07-12 17:49:57 +07:00
Aswin Ashar Abdullah 2ed4ce0199 feat(SPG-389) REST API CUD Refund 2024-07-12 17:30:15 +07:00
Aswin Ashar Abdullah 66fd9c16b2 fix(SPG-595) Pemesanan - Penyesuaian flow booking
continuous-integration/drone/tag Build is passing Details
2024-07-11 21:51:08 +07:00
Aswin Ashar Abdullah 9242f43760 fix(SPG-595) Pemesanan - Penyesuaian flow booking 2024-07-11 18:14:05 +07:00
Aswin Ashar Abdullah de2041ae95 fix(SPG-595) Pemesanan - Penyesuaian flow booking 2024-07-11 17:30:47 +07:00
aswin eb32584205 Merge pull request 'fix(SPG-595) Pemesanan - Penyesuaian flow booking' (#26) from fix/transaction into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #26
2024-07-10 10:38:52 +00:00
Aswin Ashar Abdullah f4969a837c fix(SPG-595) Pemesanan - Penyesuaian flow booking 2024-07-10 17:37:43 +07:00
Firman Ramdhani 59cf933abc feat: fix export group
continuous-integration/drone/tag Build is passing Details
2024-07-09 19:28:11 +07:00
Firman Ramdhani 2f03f18d51 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-07-09 18:44:12 +07:00
Firman Ramdhani 12543ea00b feat: adjustment api get config report 2024-07-09 18:44:05 +07:00
irfan c9b55c3d91 Merge pull request 'fix/type-data' (#25) from fix/type-data into development
Reviewed-on: #25
2024-07-09 11:25:20 +00:00
shancheas 0d7951d5f0 ci: update env COUCHDB_CONFIG 2024-07-09 18:13:38 +07:00
shancheas 34909a30b0 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/type-data 2024-07-09 17:53:37 +07:00
Aswin Ashar Abdullah 99847ce85b fix(SPG-593) Pemesanan - Update Pembayaran Pending - Tambahkan informasi pembayaran via dan no rekening 2024-07-09 17:52:46 +07:00
Aswin Ashar Abdullah 28dcac39f0 feat(SPG-405) DB Kode Diskon VIP 2024-07-09 17:52:04 +07:00
shancheas 6261592339 lint: update type data and lint 2024-07-09 17:47:15 +07:00
shancheas c87c852509 fix: update nano db configuration 2024-07-09 17:37:22 +07:00
shancheas 99261f37cd fix: change String type data to string 2024-07-09 17:20:10 +07:00
firmanr 56e7d25acd Merge pull request 'feat: fix filter boolean' (#24) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #24
2024-07-08 23:09:43 +00:00
Firman Ramdhani 66a5245e61 feat: fix filter boolean 2024-07-08 20:51:31 +07:00
aswin d149a15530 Merge pull request 'fix/transaction' (#23) from fix/transaction into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #23
2024-07-08 11:11:24 +00:00
Aswin Ashar Abdullah 0df0f30de5 fix(format) perbaikan formatting 2024-07-08 18:10:28 +07:00
Aswin Ashar Abdullah bc25b9d020 fix(SPG-595) Pemesanan - Penyesuaian flow booking 2024-07-08 18:10:09 +07:00
Aswin Ashar Abdullah df1b130dc6 fix(SPG-547) GET POS Transaction (Akumulasi Per Hari) 2024-07-08 18:09:18 +07:00
firmanr 3f33ab6850 Merge pull request 'feat/report' (#22) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #22
2024-07-08 10:37:28 +00:00
Firman Ramdhani fa2bbbf5e2 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-07-08 17:36:08 +07:00
Firman Ramdhani be738bb49b feat: setup report transaction 2024-07-08 17:35:16 +07:00
firmanr edf8ab173d Merge pull request 'feat/report' (#21) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #21
2024-07-08 10:16:16 +00:00
Firman Ramdhani 7e50ef1bf8 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-07-08 17:14:04 +07:00
Firman Ramdhani 677732d511 feat: adjustment dto create export 2024-07-08 16:52:23 +07:00
irfan f023e01c6c docs: add formula calculation documentation 2024-07-08 09:46:48 +00:00
Firman Ramdhani 32ae6481e6 feat: get current applied bookmark 2024-07-08 16:22:55 +07:00
Aswin Ashar Abdullah 389c26e1b0 feat(SPG-585) DB COUCH Booking 2024-07-08 15:39:42 +07:00
Firman Ramdhani 2038f0a74f feat: add condition on create bookmark 2024-07-08 13:43:22 +07:00
firmanr 1827cdb592 Merge pull request 'feat: set default file name on export' (#20) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #20
2024-07-08 05:48:47 +00:00
Firman Ramdhani a2e05b4d59 feat: set default file name on export 2024-07-08 12:48:28 +07:00
firmanr 94bb218d50 Merge pull request 'feat: set default file name on export' (#19) from feat/report into development
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #19
2024-07-08 05:41:16 +00:00
Firman Ramdhani d48ac84244 feat: set default file name on export 2024-07-08 12:39:49 +07:00
firmanr 91a01a2857 Merge pull request 'feat/report' (#18) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #18
2024-07-08 05:36:49 +00:00
Firman Ramdhani 313843591e Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-07-08 12:36:06 +07:00
Firman Ramdhani 36b48b9257 feat: set default file name on export 2024-07-08 12:35:42 +07:00
aswin b6d067c9cd Merge pull request 'fix/transaction' (#17) from fix/transaction into development
Reviewed-on: #17
2024-07-08 04:59:56 +00:00
Aswin Ashar Abdullah 40c92dacd1 fix(SPG-595) Pemesanan - Penyesuaian flow booking 2024-07-08 11:58:48 +07:00
Aswin Ashar Abdullah 1cd933d64f fix(SPG-592) Pemesanan - List Item - Saat update data tidak tersimpan 2024-07-08 11:58:03 +07:00
Aswin Ashar Abdullah 4aa03226de fix(SPG-594) Pemesanan - Index - Belum ada kolom informasi tgl.update 2024-07-08 11:57:09 +07:00
Aswin Ashar Abdullah 0db0f75cb9 fix(SPG-591) Pemesanan - Konfirmasi dari status pending muncul warning 2024-07-08 11:56:23 +07:00
firmanr e99071f9ce Merge pull request 'fix: fixed typo module key' (#16) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #16
2024-07-05 09:12:57 +00:00
Firman Ramdhani 8cdf75c2a0 fix: fixed typo module key 2024-07-05 16:09:24 +07:00
firmanr d2fd665236 Merge pull request 'feat: edit privilege configuration menu' (#15) from feat/report into development
continuous-integration/drone/tag Build encountered an error Details
Reviewed-on: #15
2024-07-05 07:45:44 +00:00
Firman Ramdhani c69bdc2295 feat: edit privilege configuration menu 2024-07-05 14:45:03 +07:00
firmanr 3e83ee3077 Merge pull request 'feat: add privilege configuration report tenant' (#14) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #14
2024-07-05 06:31:08 +00:00
Firman Ramdhani ce6343dfa2 feat: add privilege configuration report tenant 2024-07-05 13:29:43 +07:00
aswin 5f3e05a9e3 Merge pull request 'fix(SPG-590) Pemesanan - Konfirmasi dari status draft muncul error' (#13) from fix/transaction into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #13
2024-07-04 23:52:28 +00:00
Aswin Ashar Abdullah cafbb82af6 fix(SPG-590) Pemesanan - Konfirmasi dari status draft muncul error 2024-07-05 06:50:33 +07:00
firmanr b9c5cb17d3 Merge pull request 'feat/report' (#12) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #12
2024-07-04 11:33:08 +00:00
Firman Ramdhani f9c36582e1 feat: integration export report 2024-07-04 18:32:03 +07:00
Firman Ramdhani ed66b88dd0 feat: integration create export report 2024-07-04 17:22:56 +07:00
Firman Ramdhani 6fbccb0c9d feat: integration feature report bookmark 2024-07-04 15:55:14 +07:00
Aswin Ashar Abdullah d4d4101d69 fix(SPG-544) BE-Validasi Tenant dan Item Tenant
continuous-integration/drone/tag Build is passing Details
2024-07-04 08:19:02 +07:00
Aswin Ashar Abdullah 5ab14f5c62 fix(SPG-566) BE - Validasi season periode tipe range date 2024-07-03 23:07:27 +07:00
firmanr 0410b481e1 Merge pull request 'feat/report' (#11) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #11
2024-07-03 11:11:21 +00:00
Firman Ramdhani fc37e0c502 feat: integration API for get data and get meta data 2024-07-03 17:03:13 +07:00
Firman Ramdhani 85d461c70a feat: setup service get report config 2024-07-03 16:05:36 +07:00
Firman Ramdhani 4dc9f7ee99 feat: setup query builder report and create sample report configuration 2024-07-03 16:04:40 +07:00
Firman Ramdhani c3ffb2b13f feat: init query builder report 2024-07-03 14:47:20 +07:00
firmanr 6bb8c928c0 Merge pull request 'feat: setup api for get label history on bookmark' (#10) from feat/report into development
Reviewed-on: #10
2024-07-03 05:22:18 +00:00
Firman Ramdhani 603632b6af feat: setup api for get label history on bookmark 2024-07-03 12:20:48 +07:00
firmanr dba03ff81c Merge pull request 'feat: create migration for add column type on report-bookmark table' (#9) from feat/report into development
Reviewed-on: #9
2024-07-03 05:02:48 +00:00
Firman Ramdhani 1d8cc6e13d feat: create migration for add column type on report-bookmark table 2024-07-03 12:01:44 +07:00
firmanr fec27cf294 Merge pull request 'feat/report' (#8) from feat/report into development
Reviewed-on: #8
2024-07-03 04:57:21 +00:00
Firman Ramdhani e2135c841f Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-07-03 11:57:00 +07:00
Firman Ramdhani 241501815b feat: update model report bookmark 2024-07-03 11:56:52 +07:00
Firman Ramdhani e586a7bad1 feat: config dto type on bookmark report 2024-07-03 11:56:00 +07:00
Firman Ramdhani c0f8d5ad9d feat: setup argument function module report 2024-07-03 11:52:12 +07:00
firmanr e139c2bcd8 Merge pull request 'feat/report' (#7) from feat/report into development
Reviewed-on: #7
2024-07-03 03:19:19 +00:00
Firman Ramdhani 35b3cfac8c Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-07-03 09:44:20 +07:00
Aswin Ashar Abdullah 5dfe9da0ff fix(couch) perbaikan couch controller
continuous-integration/drone/tag Build is passing Details
2024-07-03 00:28:41 +07:00
aswin 0a7678471d Merge pull request 'feat/transaction' (#6) from feat/transaction into development
Reviewed-on: #6
2024-07-02 17:09:18 +00:00
Aswin Ashar Abdullah 7bd66b47a4 Merge remote-tracking branch 'origin/development' into feat/transaction 2024-07-02 23:55:03 +07:00
Aswin Ashar Abdullah ac522bc55a feat(SPG-384) REST API Read Booking 2024-07-02 23:38:41 +07:00
Aswin Ashar Abdullah 36d430484e feat(SPG-383) REST API CUD Booking/Pemesanan 2024-07-02 23:12:55 +07:00
Aswin Ashar Abdullah db005426bd feat(SPG-395) REST API Read Rekonsiliasi 2024-07-02 21:45:51 +07:00
Aswin Ashar Abdullah a84a48c292 feat(SPG-394) REST API CU MDR 2024-07-02 21:45:04 +07:00
Firman Ramdhani f62dc15075 feat: setup router report 2024-07-02 17:09:07 +07:00
Firman Ramdhani e51e5a51a1 feat: init module report 2024-07-02 16:42:16 +07:00
Aswin Ashar Abdullah 8db2256852 fix(couch) perbaikan sync data couch
continuous-integration/drone/tag Build is passing Details
2024-07-01 08:50:42 +07:00
Aswin Ashar Abdullah 0b1cdabea4 format(code) formatting code 2024-07-01 01:13:26 +07:00
Aswin Ashar Abdullah 4b31dd40b5 fix(SPG-573) Validasi season period tipe specific days - sekalipun harinya berbeda masih terkena validasi, seharusnya bisa disimpan 2024-06-30 23:55:56 +07:00
Aswin Ashar Abdullah 3bb6ed1082 fix(SPG-571) error / Loading saat delete (bulk atau satuan) - ( pengaruh ke tab lain ) berlaku untuk semua module 2024-06-30 23:06:19 +07:00
Aswin Ashar Abdullah ced08bebd3 fix(SPG-572) Validasi "Belum memiliki periode season" jika menambahkan harga/item rate pada season yang belum memiliki periode season 2024-06-30 22:54:20 +07:00
Aswin Ashar Abdullah 8ce58981c7 wip-feat(SPG-383) REST API CUD Booking/Pemesanan 2024-06-28 18:18:35 +07:00
Aswin Ashar Abdullah 1e0766dc50 fix(SPG-566) BE - Validasi season periode tipe range date
continuous-integration/drone/tag Build is passing Details
2024-06-26 17:33:14 +07:00
aswin 9f471aafbf Merge pull request 'wip-SPG-548' (#5) from wip-SPG-548 into development
Reviewed-on: #5
2024-06-26 06:52:24 +00:00
Aswin Ashar Abdullah 03769873d0 wip-feat(SPG-548) CouchDB Data - Login, Item, Metode Pembayaran, Kategori VIP, Season Period 2024-06-26 13:50:14 +07:00
firmanr 67d0b4b262 Merge pull request 'feat/report' (#4) from feat/report into development
Reviewed-on: #4
2024-06-25 06:54:11 +00:00
Firman Ramdhani c862bf2289 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/report 2024-06-25 13:53:49 +07:00
Firman Ramdhani 655229ddbd feat: setup migration table report 2024-06-25 13:53:09 +07:00
Aswin Ashar Abdullah bc296cc52a fix(SPG-559) Item rate - index - search masih belum bisa (masih menampilkan semua data) 2024-06-25 13:49:46 +07:00
Firman Ramdhani 0bed18b439 feat: ini shared content report 2024-06-25 13:45:23 +07:00
firmanr c35f966b5a Merge pull request 'feat: move api versioning' (#3) from feat/report into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #3
2024-06-25 05:24:42 +00:00
Firman Ramdhani cb8b1bfd6b feat: move api versioning 2024-06-25 12:24:17 +07:00
Aswin Ashar Abdullah 0368f3452b fix(SPG-552) BE - Update Item Rate pada module season period
continuous-integration/drone/tag Build is passing Details
2024-06-24 20:04:14 +07:00
Aswin Ashar Abdullah cc7a345fff fix(SPG-549) BE - Validasi tgl periode unique based on level 2024-06-24 18:26:48 +07:00
Aswin Ashar Abdullah 067025312e fix(SPG-550) Season Period - Generate hari libur belum terfilter berdasarkan periode tanggal 2024-06-24 16:01:06 +07:00
Aswin Ashar Abdullah 5fa89e8666 fix(SPG-551) Item rate - index - muncul error "Cannot read properties of null (reading 'start_date')" saat mengakses index 2024-06-24 15:40:45 +07:00
Aswin Ashar Abdullah bc0d8cbb10 fix(index) perbaikan sorting index 2024-06-20 17:17:11 +07:00
Aswin Ashar Abdullah 9445d561ac fix(paginate) perbaikan function pagination endpoint
continuous-integration/drone/tag Build is passing Details
2024-06-20 16:26:02 +07:00
Aswin Ashar Abdullah 23f5ed0946 fix(SPG-543) BE-Validasi Data Tax - data tidak bisa di delete dan di inactivekan jika dipakai di formula 2024-06-20 16:07:07 +07:00
Aswin Ashar Abdullah 507bc99510 fix(SPG-541) BE- Ganti nama module tipe rate ke season 2024-06-20 15:30:22 +07:00
Aswin Ashar Abdullah 9315854143 fix(item rate) penyesuaian endpoint get item rates paginate
continuous-integration/drone/tag Build is passing Details
2024-06-20 15:23:25 +07:00
Aswin Ashar Abdullah 84bf55011d fix(relasi) penambahan relasi tenant get 2024-06-20 15:22:56 +07:00
Aswin Ashar Abdullah 766909798f fix(SPG-544) BE-Validasi Tenant dan Item Tenant 2024-06-20 15:16:43 +07:00
aswin f170c2e017 Merge pull request 'wip-season-period' (#2) from wip-season-period into development
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #2
2024-06-19 22:16:53 +00:00
Aswin Ashar Abdullah a3d67ff5be feat(SPG-372) REST API Read Item Rate 2024-06-20 05:14:06 +07:00
ashar 86f81f3027 feat(SPG-367) REST API CUD Item Rate 2024-06-20 01:47:56 +07:00
ashar 54c5738676 feat(SPG-353) REST API CUD Season Period 2024-06-20 01:46:59 +07:00
ashar 5b5c3efccc feat(SPG-355) REST API Read Season Period 2024-06-20 01:46:09 +07:00
ashar 08dea7965d feat(google-calendar) module google calendar 2024-06-20 01:44:41 +07:00
ashar 99a82c164a fix(package) penambahan package
continuous-integration/drone/tag Build is passing Details
2024-06-19 16:58:31 +07:00
ashar f159b905ec fix(SPG-538) BE - Formula - Muncul Error saat save - Cannot read properties of null
continuous-integration/drone/tag Build is failing Details
2024-06-19 12:43:39 +07:00
ashar bc8b79b9c9 fix(SPG-536) Search Metode Pembayaran by Tipe Error 2024-06-19 12:42:43 +07:00
ashar 5880a6051f fix(SPG-524) BE - Create item wahana - Error constraint value limit 2024-06-19 12:42:13 +07:00
ashar 554cda2144 feat(SPG-476) Google Calendar Integration - Hari Libur 2024-06-18 15:03:55 +07:00
ashar af6266c8d6 fix(SPG-525) BE-Form Tax-Value Tax bisa koma - float 2024-06-18 09:01:12 +07:00
ashar 84e65d2599 fix(SPG-535) BE - Update Tenant - Muncul warning email must be an email ketika save padahal email tidak diubah (sama dengan ketika create) 2024-06-18 08:54:09 +07:00
ashar aa3c8fa359 fix(constant) penambahan endpoint constant payment type
continuous-integration/drone/tag Build is passing Details
2024-06-12 17:16:37 +07:00
ashar 1ebf6a5c30 feat(SPG-380) REST API Read Metode Pembayaran
continuous-integration/drone/tag Build is passing Details
2024-06-12 14:37:28 +07:00
ashar 30b8aa2083 deat(SPG-380) REST API Read Metode Pembayaran
continuous-integration/drone/tag Build is failing Details
2024-06-12 11:57:17 +07:00
ashar 0ce8c8402e feat(SPG-379) REST API CUD Metode Pembayaran 2024-06-12 11:47:44 +07:00
ashar d9d22779f0 feat(SPG-487) REST API CU Profit Share Formula 2024-06-12 11:21:22 +07:00
ashar f7d5a5ca5f feat(SPG-483) REST API CU Formula Harga Jual 2024-06-12 11:08:30 +07:00
ashar d98f16b1bf fix(item) perbaikan dto item bundling
continuous-integration/drone/tag Build is passing Details
2024-06-12 10:48:01 +07:00
ashar f9e9818af9 fix(item) perbaikan dto item bundling
continuous-integration/drone/tag Build is passing Details
2024-06-12 10:31:49 +07:00
ashar abe163e80a feat(SPG-331) REST API Read Tax 2024-06-12 10:09:38 +07:00
ashar d7937217ab feat(SPG-330) REST API CUD Tax Data 2024-06-12 10:09:21 +07:00
ashar 73547451d4 feat(SPG-349) REST API Read Tipe Season 2024-06-12 09:50:36 +07:00
ashar 446295ee16 feat(SPG-347) REST API CUD Tipe Season 2024-06-12 09:46:43 +07:00
ashar 50cbaa38c1 fix(item) perbaikan module item
continuous-integration/drone/tag Build is passing Details
2024-06-11 16:25:23 +07:00
ashar 321d13568f feat(enum) penambahan endpoint limit type
continuous-integration/drone/tag Build is passing Details
2024-06-11 15:42:53 +07:00
ashar afbf22cc03 feat(relation) perbaikan validasi relasi item
continuous-integration/drone/tag Build is passing Details
2024-06-11 15:37:56 +07:00
ashar 3f3da30c37 feat(SPG-361) REST API Read Item/ Tenant Item 2024-06-11 15:31:55 +07:00
ashar b2b0ade6b4 feat(SPG-359) REST API CUD Item / Tenant Item 2024-06-11 15:07:03 +07:00
ashar f5c4b1ffdf fix(SPG-509) BE - Create/ Update Tenant - Muncul Error email not valid ketika email address panjang, padahal struktur sudah bentuk email 2024-06-11 11:38:28 +07:00
ashar a126dd267c fix(template) perbaikan template generator module
continuous-integration/drone/tag Build is passing Details
2024-06-11 11:16:29 +07:00
ashar f86f86fe0c feat(SPG-54) REST API Create VIP Code Disc 2024-06-11 11:16:13 +07:00
ashar f4cc5ae1c9 fix(template) perbaikan template generator module 2024-06-11 09:05:32 +07:00
ashar d98246063d feat(SPG-374) REST API Read Kategori VIP 2024-06-11 09:05:03 +07:00
ashar be7eb23c97 feat(SPG-373) REST API CUD Kategori VIP 2024-06-11 09:04:43 +07:00
ashar fd5cb0062d fix(tenant) perbaikan detail tenant
continuous-integration/drone/tag Build is passing Details
2024-06-11 08:54:37 +07:00
ashar 74ccb047b1 fix(tenant) perbaikan index tenant
continuous-integration/drone/tag Build is passing Details
2024-06-11 08:39:16 +07:00
ashar cf46b2fd4c fix(login) penyesuaian response login
continuous-integration/drone/tag Build is passing Details
2024-06-10 17:11:22 +07:00
ashar f4ddbe08a8 docs(filter) dokumentasi filter search enum
continuous-integration/drone/tag Build is passing Details
2024-06-10 16:01:15 +07:00
ashar a8322e13e5 fix(SPG-503) BE - Search by Status - Dapat melakukan pencarian dgn sebagian huruf, tanpa mengeluarkan ERR row 2024-06-10 15:59:10 +07:00
ashar f35aa7412f docs(template) penambahan doc 2024-06-10 15:37:42 +07:00
ashar 33f269b56b feat(SPG-336) REST API Read Item Category 2024-06-10 15:37:24 +07:00
ashar 63b9a3028a fix(user-privilege) perbaikan validasi delete inactive related 2024-06-10 15:14:30 +07:00
ashar 14559290cf feat(SPG-335) REST API CRUD Item Category 2024-06-10 15:14:09 +07:00
ashar 417e90dbc5 feat(SPG-325) REST API Read Users
continuous-integration/drone/tag Build is passing Details
2024-06-10 14:14:34 +07:00
ashar cfb896921b feat(SPG-324) REST API CUD Users 2024-06-10 13:54:40 +07:00
ashar 9431e27013 feat(SPG-341) REST API Read Data Tenant
continuous-integration/drone/tag Build is passing Details
2024-06-10 12:14:05 +07:00
ashar ac31c0c2f9 feat(SPG-340) REST API CUD Tenant 2024-06-10 11:31:46 +07:00
ashar d5f0fe6517 fix(format) perbaikan formatting 2024-06-10 11:30:45 +07:00
ashar caa9ea14fc fix(validate) perbaikan validasi duplicate column 2024-06-10 11:29:59 +07:00
ashar 91dc7ad5b4 fix(dockerfile) perbaikan dockerfile ketimpa 2024-06-07 14:31:44 +07:00
ashar e9d2ba952c feat(SPG-10) Research & Testing PG to Couch, Couch to PG 2024-06-07 09:49:43 +07:00
Derit Agustin 71c3f91a52 update env new db
continuous-integration/drone/tag Build is passing Details
2024-06-07 02:00:03 +00:00
shancheas 9ff1012813 debug: add debug log when login
continuous-integration/drone/tag Build is passing Details
2024-06-06 17:33:45 +07:00
ashar 26a073968f fix(filter) perbaikan sorting
continuous-integration/drone/tag Build is passing Details
2024-06-06 15:46:49 +07:00
ashar c5c5762823 feat(SPG-7) Data Validation 2024-06-06 14:59:51 +07:00
ashar 5802dc3c92 fix(service) inject manager 2024-06-06 14:05:01 +07:00
ashar 1abb30649a fix(service) inject manager 2024-06-06 14:04:12 +07:00
ashar 4fc428e3b7 fix(event) perbaikan extend event 2024-06-06 14:03:43 +07:00
ashar 7bd79bffd2 fix(format) formatting 2024-06-06 14:03:17 +07:00
ashar 63a849ed7b feat(SPG-497) Generator Module 2024-06-06 14:02:21 +07:00
aswin 1a3ecefa0a revert 47aa9bef55
continuous-integration/drone/tag Build is passing Details
revert fix(sorting) perbaikan sorting data
2024-06-06 04:56:55 +00:00
ashar 47aa9bef55 fix(sorting) perbaikan sorting data
continuous-integration/drone/tag Build is passing Details
2024-06-06 11:25:41 +07:00
ashar eb90b43429 fix(no-card) penyesuaian filter user privilege configuration
continuous-integration/drone/tag Build is passing Details
2024-06-05 16:31:50 +07:00
ashar 6165763a0b feat(format) formatting
continuous-integration/drone/tag Build is passing Details
2024-06-05 14:37:03 +07:00
ashar ca45d78e1d feat(event) interface event
continuous-integration/drone/tag Build is passing Details
2024-06-05 13:58:09 +07:00
ashar f9ec18ff28 feat(SPG-329) BE Logout Web Admin
continuous-integration/drone/tag Build is failing Details
2024-06-05 13:55:04 +07:00
ashar df6adf0e0f feat(SPG-328) BE Login Web Admin 2024-06-05 13:54:31 +07:00
ashar 1aae9d0a1b Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-06-05 09:30:33 +07:00
ashar f36e3b26d4 feat(SPG-125) wip Logging 2024-06-05 09:29:43 +07:00
Derit Agustin ede43c1b91 update deploy url 2024-06-04 09:11:05 +00:00
ashar cefff6d5c7 feat(seeder) seeder data user privilege 2024-06-04 15:54:16 +07:00
ashar 6596c776e8 feat(SPG-5) Filter 2024-06-04 15:52:33 +07:00
Derit Agustin d3dce3990d fix deploy
continuous-integration/drone/tag Build is passing Details
2024-06-04 08:35:54 +00:00
Derit Agustin d83028e148 fix
continuous-integration/drone/tag Build encountered an error Details
2024-06-04 08:31:25 +00:00
Derit Agustin c719102b60 fix 2024-06-04 06:45:54 +00:00
Derit Agustin b4f868f738 fix docker
continuous-integration/drone/tag Build is passing Details
2024-06-04 06:15:32 +00:00
ashar 1ac5aca57d feat(data) seed default admin
continuous-integration/drone/tag Build is passing Details
2024-06-04 10:11:07 +07:00
Derit Agustin 1641c81a53 fix 2024-06-03 22:01:01 +00:00
Derit Agustin e5da3d1cba add ci deployment step
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details
2024-06-03 15:01:33 +00:00
Derit Agustin 8b7d1fcd24 fix tag
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build is passing Details
2024-06-03 14:18:39 +00:00
Derit Agustin 1ef5404853 fix 2024-06-03 14:13:08 +00:00
Derit Agustin 2fccb2b8e9 fix 2024-06-03 14:07:22 +00:00
Derit Agustin c7d09a00b5 fix version 2024-06-03 14:05:51 +00:00
Derit Agustin f20fc252c7 fix ci build title 2024-06-03 13:30:23 +00:00
Derit Agustin 8fc61a697f add ci/cd
continuous-integration/drone/tag Build is passing Details
2024-06-03 13:26:14 +00:00
Derit Agustin 41330cc74a add dockerfile 2024-06-03 10:32:22 +00:00
ashar da9145078c Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into skyworld-implementation 2024-06-03 16:23:30 +07:00
ashar 35b9ffd306 feat(migrasi) config migrasi 2024-06-03 16:22:13 +07:00
ashar f5c1008ece feat(SPG-124) Authorization 2024-06-03 16:13:11 +07:00
ashar 34ea6a501d feat(package) update package 2024-06-03 15:35:48 +07:00
ashar 98f9fecc27 feat(SPG-123) Abstraction Transaction Data 2024-06-03 15:35:00 +07:00
ashar e442ca717e feat(SPG-321) REST API Read User Privileges 2024-06-03 15:30:58 +07:00
ashar af06f2d08e feat(SPG-6) Authentication 2024-06-03 15:22:42 +07:00
ashar 240bbf4c2e feat(SPG-320) REST API CUD User Privileges 2024-06-03 15:18:17 +07:00
ashar c0b0ffa8fa feat(SPG-496) Model Users 2024-06-03 15:14:07 +07:00
ashar b945ef1e10 feat(SPG-126) Monitoring APM 2024-05-31 11:07:34 +07:00
ashar 9ce4c58dc1 feat(SPG-123) Abstraction Transaction Data 2024-05-31 11:06:50 +07:00
aswin 46b8d50078 Merge pull request 'master' (#1) from master into development
Reviewed-on: #1
2024-05-30 02:44:31 +00:00
1138 changed files with 70353 additions and 2021 deletions

109
.drone.yml Normal file
View File

@ -0,0 +1,109 @@
kind: pipeline
type: docker
name: server
steps:
# - name: build
# image: appleboy/drone-ssh
# settings:
# host:
# - 172.10.10.10
# username: eigen
# key:
# from_secret: DEVOPS_SSH_PRIVATE_OPEN
# port: 22
# script:
# - cd /home/eigen/PROJECT/POS/POS.DEV/BE
# - sh build.sh
# when:
# ref:
# - refs/tags/devel_*
# - refs/tags/*-alpha.*
- name: build-testing
image: plugins/docker
settings:
registry: registry.eigen.co.id
repo: registry.eigen.co.id/eigen/${DRONE_REPO_NAME}
tags: ${DRONE_TAG}
custom_dns: 172.10.10.16
when:
ref:
- refs/tags/*-alpha.*
- name: build-production
image: plugins/docker
settings:
registry: registry.eigen.co.id
repo: registry.eigen.co.id/eigen/${DRONE_REPO_NAME}
tags: ${DRONE_TAG}
custom_dns: 172.10.10.16
when:
ref:
- refs/tags/*-production.*
- name: send-message
image: plugins/webhook
settings:
urls: https://mattermost.eigen.co.id/api/v4/posts
content_type: application/json
headers:
- Authorization=Bearer 5zubexudb38uuradfa36qy98ca
template: |
{
"channel_id": "s1ekqde1c3du5p35g6budnuotc",
"message": "Build {{repo.name}} sudah selesai"
}
trigger:
event:
exclude:
- promote
---
kind: pipeline
type: docker
name: kustomize
clone:
disable: true
steps:
- name: kustomize-testing
image: registry.k8s.io/kustomize/kustomize:v5.0.0
environment:
DEVOPS_SSH_PRIVATE:
from_secret: DEVOPS_SSH_PRIVATE
DEVOPS_SSH_PUBLIC:
from_secret: DEVOPS_SSH_PUBLIC
INFRASTRUCTURE_REPO: "k8s-kustomize-external"
DIRECTORY_NAME: "weplay-pos-testing"
commands:
- mkdir -p ~/.ssh &&
- echo $DEVOPS_SSH_PRIVATE | base64 -d > ~/.ssh/id_rsa &&
- echo $DEVOPS_SSH_PUBLIC | base64 -d > ~/.ssh/id_rsa.pub &&
- ssh-keyscan -H -p 2222 git.eigen.co.id >> ~/.ssh/known_hosts &&
- chmod 700 ~/.ssh/ &&
- chmod 600 ~/.ssh/id_rsa &&
- git clone ssh://git@git.eigen.co.id:2222/eigen/$INFRASTRUCTURE_REPO.git &&
- cd $INFRASTRUCTURE_REPO/$DIRECTORY_NAME
- kustomize edit set image registry.eigen.co.id/eigen/$DRONE_REPO_NAME=registry.eigen.co.id/eigen/$DRONE_REPO_NAME:$DRONE_TAG &&
- git add . &&
- |-
git commit -m "feat: update $DRONE_REPO_NAME testing to $DRONE_TAG" &&
- git push origin master
- name: send-message
image: harbor.eigen.co.id/docker.com/plugins/webhook
settings:
urls: https://mattermost.eigen.co.id/api/v4/posts
content_type: application/json
headers:
- Authorization=Bearer 5zubexudb38uuradfa36qy98ca
template: |
{
"channel_id": "s1ekqde1c3du5p35g6budnuotc",
"message": "ALERT: {{ repo.name }} gagal update dengan tag ${DRONE_TAG}"
}
when:
status:
- failure
trigger:
ref:
include:
- refs/tags/*-alpha.*
depends_on:
- server

38
.drone.yml.old Normal file
View File

@ -0,0 +1,38 @@
kind: pipeline
type: docker
name: build
steps:
- name: build-dev
image: plugins/docker
settings:
registry: registry.eigen.co.id
repo: registry.eigen.co.id/eigen/${DRONE_REPO_NAME}
build_args:
- env_target=env.development
tags: latest
custom_dns: 172.10.10.16
trigger:
ref:
- refs/tags/devel_*
event:
exclude:
- promote
---
kind: pipeline
type: docker
name: deployment
steps:
- name: deployment
image: alpine
failure: ignore
commands:
- apk add --no-cache curl
- curl -X POST https://manager.sky.eigen.co.id/api/webhooks/806de7e2-1d3e-4889-b472-a59af0a5eb33
trigger:
ref:
- refs/tags/devel_*
event:
exclude:
- promote
depends_on:
- build

32
.drone.yml.save Normal file
View File

@ -0,0 +1,32 @@
kind: pipeline
type: docker
name: build
steps:
- name: build-dev
image: plugins/docker
trigger:
ref:
- refs/tags/devel_*
event:
exclude:
- promote
---
kind: pipeline
type: docker
name: deployment
steps:
- name: deployment
image: alpine
failure: ignore
commands:
- apk add --no-cache curl
- curl -X POST https://manager.sky.eigen.co.id/api/webhooks/09856c08-cf1e-493f-a302-d7cd65b22384
trigger:
ref:
- refs/tags/devel_*
event:
exclude:
- promote
depends_on:
- build

27
.drone.yml.save.1 Normal file
View File

@ -0,0 +1,27 @@
kind: pipeline
type: docker
name: build
steps:
- name: build-dev
image: plugins/docker
settings:
registry: registry.eigen.co.id
repo: registry.eigen.co.id/eigen/${DRONE_REPO_NAME}
build_args:
- env_target=env.development
tags: latest
custom_dns: 172.10.10.16
- name: deployment
image: alpine
failure: ignore
commands:
- apk add --no-cache curl
- curl -X POST https://manager.sky.eigen.co.id/api/webhooks/09856c08-cf1e-493f-a302-d7cd65b22384
trigger:
ref:
- refs/tags/devel_*
event:
exclude:
- promote
depends_on:
- build

7
.gitignore vendored
View File

@ -30,7 +30,12 @@ lerna-debug.log*
# IDE - VSCode # IDE - VSCode
.vscode/* .vscode/*
.env .env
.dockerignore
docker-compose.yml
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
# IGNORE UPLOAD FOLDER
/uploads

20
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Nest Framework",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start:debug", "--", "--inspect-brk"],
"autoAttachChildProcesses": true,
"restart": true,
"sourceMaps": true,
"stopOnEntry": false,
"console": "integratedTerminal"
}
]
}

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM node:18.17-alpine as builder
RUN apk add --no-cache git
WORKDIR /app
COPY . .
RUN yarn install
RUN yarn build
FROM node:18.17-alpine
# ARG env_target
WORKDIR /app
# RUN echo ${env_target}
# COPY env/$env_target /app/.env
# COPY --from=builder /app/env/$env_target .env
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/assets ./assets
COPY --from=builder /app/package.json ./package.json
CMD ["node", "--max-old-space-size=8192","--max-http-header-size", "512000", "-r", "dotenv/config", "dist/main"]

View File

@ -0,0 +1,404 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p class="mb0">Great News! We've successfully updated your booking date as per your request.</p>
<p>We're excited to accommodate your new plans and ensure evertyhing goes smoothly.</p>
<p class="mb0">Here are your updated booking details</p>
<b class="mb0">Original Booking Date: {{booking_date_before}}</b>
<b>New Booking Date: {{booking_date}}</b>
<p class="mb0">For yout convenience, we've attached a new confirmation receipt reflecting these changes.</p>
<p><b>Please be sure to bring this updated receipt with you on the new date</b></p>
<p class="mb0">To keep the good times rolling, our friendly support team is just a call away at</p>
<b>{{phone_cs}}</b>
<br>
<p>Thank you and we can't wait to see you and make sure you have an amazing time!</p>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,412 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p>Thank you fot choosing us! We're absolutelty thrilled and can't wait to embark on this exciting day with you. See you soon for fun times ahead</p>
<p class="mb0">Here's a quick recap of your invoice:</p>
<p class="mb0">Booking Date: {{booking_date}}</p>
<p>Total Invoice: {{payment_total}}</p>
<p class="mb0">Just a friendly reminder that your invoice will expire on {{expire_date}}</p>
<p>To keep things running smoothly, please ensure your payment is completed before this data</p>
<p>
For your convenience, here is a list of our account details:
<ul>
{{#each payment_methods}}
<li>
<p>{{issuer_name}} {{account_number}} a/n >{{account_name}}</p>
</li>
{{/each}}
</ul>
</p>
<p class="mb0">Once you've made the payment, please kindly email or send the proof of payment so we can proceed with your booking promptly</p>
<p class="mb0">If you have any questions or need assistance, feel free to reach out to our support team at</p>
<b>{{phone_cs}}</b>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,400 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p>We hope this message finds you well!</p>
<p class="mb0">Uh-oh! it looks like your invoice, dated {{invoice_date}}, has officially expired as of {{expired_date}}</p>
<p>But no worries, we can fix this together!</p>
<p class="mb0">To keep the good times rolling, our friendly support team is just a call away at</p>
<b>{{phone_cs}}</b>
<p class="mb0">Here are the details of the expired invoice:</p>
<p class="mb0">Booking Date: {{booking_date}}</p>
<p>Total Invoice: {{total_payment}}</p>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,419 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p>Thank you fot choosing us! We're absolutelty thrilled and can't wait to embark on this exciting day with you. See you soon for fun times ahead</p>
<p class="mb0">Here's a quick recap of your invoice:</p>
<p class="mb0">Booking Date: {{booking_date}}</p>
<p>Total Invoice: {{payment_total}}</p>
<p class="mb0">Just a friendly reminder that your invoice will expire on {{expire_date}}</p>
<p>To keep things running smoothly, please ensure your payment is completed before this data</p>
<p class="mb0">For your convenience, here is a list of our account details:</p>
<a href="{{payment_midtrans_url}}">{{payment_midtrans_url}}</a>
<br><br>
<p class="mb0">Once you've made the payment, please kindly email or send the proof of payment so we can proceed with your booking promptly</p>
<p class="mb0">If you have any questions or need assistance, feel free to reach out to our support team at</p>
<b>{{phone_cs}}</b>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- START FOOTER -->
<!-- <div class="footer">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block powered-by">
Powered by Skyworld
</td>
</tr>
</table>
</div> -->
<!-- END FOOTER -->
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,412 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p class="mb0">We are excited to inform you that your payment has been successfully received!</p>
<p class="mb0">Attached to this email, you will find your confirmatin receipt</p>
<p class="mb0">Please keep this safe as you will need to show it at the entrance upon your arrival</p>
<p>It's your golden ticket to all the fun and excitement awaiting you!</p>
<br>
<p class="mb0">Here's a quick recap:</p>
<p class="mb0">Booking Date: {{booking_date}}</p>
<p class="mb0">Invoice Code: {{invoice_code}}</p>
<p class="mb0">Payment Date: {{payment_date}}</p>
<p class="mb0">Payment Code: {{payment_code}}</p>
<p class="mb0">Payment Via: {{payment_via}}</p>
<p class="mb0">Account No: {{account_no}}</p>
<p>On Behalf Of: {{account_name}}</p>
<br>
<p class="mb0">If you have any questions or need assistance, feel free to reach out to our support team at</p>
<b>{{phone_cs}}</b>
<br>
<p class="mb0">Font forget to bring a smile and your confirmation receipt (attached) for a smooth entry</p>
<p>We can't wait to see you and ensure you have an amazing time with us!</p>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,415 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p class="mb-0">Good News!</p>
<p>We've successfully processed your refund for:</p>
<p class="mb0">Here are the details of your refund:</p>
<p class="mb0">Transaction Date: <b>{{booking_date}}</b></p>
<p class="mb0">Transaction Code: <b>{{invoice_code}}</b></p>
<p class="mb0">Total Refund: <b>{{refund.refund_total}}</b></p>
<p>{{{refund_items}}}</p>
<p class="mb0">Transaction Number: <b>{{invoice_code}}</b></p>
<p class="mb0">Refund Processed Date: <b>{{refund.refund_date}}</b></p>
<p class="mb0">Bank Account: <b>{{refund.bank_name}}</b></p>
<p class="mb0">Account Number: <b>{{refund.bank_account_number}}</b></p>
<p>Account Name: <b>{{refund.bank_account_name}}</b></p>
<p class="mb0">We hope this helps make things right, and we're here to assist if you need anything else</p>
<p>You should see the refund in your account within 3 business days</p>
<p class="mb0">Thank you for your patience and understanding</p>
<p>If you have any questions or need further assistance, don't hesitate to reach out us at</p>
<b>{{phone_cs}}</b>
<br>
<p class="mb0">Thank you and we can't wait to see you and make sure you have an amazing time!</p>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,409 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email Confirmation</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
width: 100%;
}
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink
down on a phone or something */
.container {
display: block;
Margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
Margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
Margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: 400;
line-height: 1.4;
margin: 0;
Margin-bottom: 30px;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
Margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn>tbody>tr>td {
padding-bottom: 15px;
}
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #3498db;
}
.btn-primary a {
background-color: #3498db;
border-color: #3498db;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
Margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
ol {
padding: 0 0 0 1em;
}
ol li {
margin: 1em 0;
}
</style>
</head>
<body class="">
<table border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="mb0"><b>Dear,</b></p>
<p class="mb0">{{customer_name}}</p>
<p>{{customer_phone}}</p>
<p class="mb0">We're trully sorry for any inconvenience that led to this request</p>
<p>We've received your refund request for :</p>
<p class="mb0">Transaction Date: <b>{{booking_date}}</b></p>
<p class="mb0">Transaction Code: <b>{{invoice_code}}</b></p>
<p class="mb0">Refund Code: <b>{{refund.code}}</b></p>
<p class="mb0">Total Refund: <b>{{refund.refund_total}}</b></p>
<p>{{{refund_items}}}</p>
<p class="mb0">Your satisfaction is important to us, and we're commited to resolving this as quickly as possible</p>
<p class="mb0">Our team is already on it and will process your refund request promptly</p>
<p>We'll keep you updated and notify you once the refund has been processed</p>
<p class="mb0">If you have any questions or need assistance, feel free to reach out to our support team at</p>
<b>{{phone_cs}}</b>
<br>
<p class="mb0">Thank you for your patience and understanding</p>
<p>We appriciate your feedback and are here to make things right</p>
<br><br>
<b>Best Regrads,</b><br>
<b>WEplayground</b>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/image/logo.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
assets/image/we.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "weplayground-app",
"private_key_id": "e3ed1a4430140ac589c6e9e7ce125d16d8f7304a",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCmEl90K7ojdx1\nnJv5BKq3THI+l+pgC4dlqOuEV4sc2SFXECgyEgEYAFH6U8eH9TTl5wW5hFhvpiWl\nHSxZA2nMa1ojp97mkufzaGgsJbcB4ni9ydoJyN9Hqs2Wz+JiBtjscGOrmOP1bNyn\nBO9RhHInh0bfTNMrtsIicr4DPNIfM2sl95v6pCDGt7Cfu2NoEnDhId50d73KVONI\n0+rf90WhehEMwoZEzYI0gLmSVbnPEm1j4/OOQfQl7FjaFKyle+A5BWaiRsIqiSue\n0jvZz0DlGmjeHx1yjBIKpq5omOku7aYi4kTNEZKKxzs5HhRFKi2KuYNK/WD5ApQg\ncIhGhhCfAgMBAAECggEANX+LmNjh9VJm/Tigkt4LFxifwgCe8WfKAhNmKHyu5K/3\nIAnzmwxjG5ee8gzNat3pfJk+dCnj7FIHwHScSB6NnCMZZXsV51sVBNC77wMxZIXA\nPyE63fzJEdlt6xvc96k9QweFB1yhs0wJ/6r2JnmcrqxcujBTUA3PIoxcG+TBOc08\ndo5Rcbeq6/3txjGlFM1820WViuFSQQiL6PgNVb+l0JrQ8rAOflKYFOkUb8wux9LX\nnD4vJMwa0j+GRvH5BCcZCguIQZn2JR3rTgcavWtcaHiTNsc49Lsj/hGGOsbkFROo\nGWaSgXE169xiVR/MMEblzqpSXq1qXF2iUeaqyUFIZQKBgQDxxrNlDs1qMfcaQ0S2\nVVtU/f1NfY+kCjQaC4CoYJaaoZINs5ODPs8/2DGnHuhNXMtnPeQ+SzNaK1e1eLbw\nmvq1+n3aGZTvUq2L3b+v7JJ6TQmQ4eBLZBzNjxrxC3EkCULTuROtsAhfzORuE0mE\nwnhR5LpPraEBrPi0re9yDDXVHQKBgQDOCwGw1gNVLh622qR65Zhx5rs2q6ktPxq2\neiUV0KDug6/7QbJzg1pNeoVQmadJR86H0fzKMsN5C7t7z3MIkqXc0+T1NmdN2fPm\ndLthnR1grCDYykoet/CITbAfiip27/o3TJ7YIYItefyZ4GnNH82R/4z3LBDnXB9f\n565hbUj76wKBgEnNMpOFijSBXgFZSU8zDPcLtNeDnWYgazkMC9DZ8v7ulOuzxjKI\n6LB/aOCvsY9z5O712IcfY2SB2HsfhxA47pDADsyVhH3tSeZo4QttdmT4wRPFrza0\nL4qbxUiRCo9KeGiylQwusM+1doEXSBjLV/j/jdOml4AwcZaNhYrVqVUNAoGAU0uD\nzXdXNZJFfGp7X+t9a155hKp05APEyswqPd1vkbzO4eY3PBd35CaJyoGzbR6IUcQE\nS8Gl4ENr8at1t5uBTfqjbrYloQVhYmMCdX3MqI4tYTa2LCD0LkYp0zZJ4Hc3Ui+5\nb2psc/ICujpMy032DvWeiTXZR46oaF8C0gQaIy0CgYEAmKCP4CXmPlWoWqebFp3W\nz2eKWUfASioQ+ZGUVNEge4a6iutciydQJZxBfg9ZXWqDfI0FoRSPfs2zUZFO0AcM\n6oaPGiFnTnH8FGcSHu3p0YysevyoSY6tgsAhb3IiKjJd4e7btsYzpPZbIfyfUVHK\nQFOOSkE+x4J5ts+XO6isQ+w=\n-----END PRIVATE KEY-----\n",
"client_email": "weplayground@weplayground-app.iam.gserviceaccount.com",
"client_id": "106351339097550564510",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/weplayground%40weplayground-app.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

View File

@ -1,17 +0,0 @@
PORT="3346"
JWT_SECRET="ftyYM4t4kjuj/0ixvIrS18gpdvBJw42NnW71GrFrEhcn0alQkkH7TQIHU5MFFJ1e"
JWT_EXPIRES="24h"
JWT_REFRESH_EXPIRES="7d"
ENC_KEY="921c83f3b90c92dca4ba9b947f99b4c9"
IV="a671a96159e97a4f"
DEFAULT_DB_HOST="localhost"
DEFAULT_DB_PORT="5432"
DEFAULT_DB_USER="postgres"
DEFAULT_DB_PASS="secret"
DEFAULT_DB_NAME="skyworld_pos"
ELASTIC_APM_ACTIVATE=true
ELASTIC_APM_SERVICE_NAME="Skyworld POS"
ELASTIC_APM_SERVER_URL="http://172.10.10.10:8200"

49
env/env.development vendored Normal file
View File

@ -0,0 +1,49 @@
PORT="3346"
JWT_SECRET="ftyYM4t4kjuj/0ixvIrS18gpdvBJw42NnW71GrFrEhcn0alQkkH7TQIHU5MFFJ1e"
JWT_EXPIRES="24h"
JWT_REFRESH_EXPIRES="7d"
ENC_KEY="921c83f3b90c92dca4ba9b947f99b4c9"
IV="a671a96159e97a4f"
COUCHDB_CONFIG="http://root:password@172.10.10.2:5970"
DEFAULT_DB_HOST="postgres"
DEFAULT_DB_PORT="5432"
DEFAULT_DB_USER="root"
DEFAULT_DB_PASS="password"
DEFAULT_DB_NAME="pos"
ELASTIC_APM_ACTIVATE=true
ELASTIC_APM_SERVICE_NAME="Skyworld POS"
ELASTIC_APM_SERVER_URL="http://172.10.10.10:8200"
CRON_MIDNIGHT="55 11 * * *"
CRON_EVERY_MINUTE="55 11 * * *"
CRON_EVERY_HOUR="0 * * * *"
EMAIL_HOST=smtp.gmail.com
EMAIL_POST=465
EMAIL_USER=weplayground.app@gmail.com
EMAIL_TOKEN="sonv vwiu khse vtmv"
// nama email yang akan muncul ke user sebagai pengirim
EMAIL_SENDER=no-reply@eigen.co.id
MIDTRANS_URL=https://app.sandbox.midtrans.com
MIDTRANS_PRODUCTION=false
MIDTRANS_SERVER_KEY=SB-Mid-server-kH9_RBZrTwaUkxSrC5vOVaeG
MIDTRANS_CLIENT_KEY=SB-Mid-client-7XLwqG5cgjUmZj-7
EXPORT_LIMIT_PARTITION=200
ASSETS="https://asset.sky.eigen.co.id/"
GOOGLE_CALENDAR_KEY="AIzaSyCSg4P3uC9Z7kD1P4f3rf1BbBaz4Q-M55o"
GOOGLE_CALENDAR_ID="326464ac296874c7121825f5ef2e2799baa90b51da240f0045aae22beec10bd5@group.calendar.google.com"
SUPERSET_URL=https://dashboard.weplayground.eigen.co.id
SUPERSET_ADMIN_USERNAME=admin
SUPERSET_ADMIN_PASSWORD=admin
WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID=604883366037548
WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV

46
env/env.production vendored Normal file
View File

@ -0,0 +1,46 @@
PORT="3346"
JWT_SECRET="ftyYM4t4kjuj/0ixvIrS18gpdvBJw42NnW71GrFrEhcn0alQkkH7TQIHU5MFFJ1e"
JWT_EXPIRES="24h"
JWT_REFRESH_EXPIRES="7d"
ENC_KEY="921c83f3b90c92dca4ba9b947f99b4c9"
IV="a671a96159e97a4f"
COUCHDB_CONFIG="http://root:password@172.10.10.2:5970"
DEFAULT_DB_HOST="postgres"
DEFAULT_DB_PORT="5432"
DEFAULT_DB_USER="root"
DEFAULT_DB_PASS="password"
DEFAULT_DB_NAME="pos"
ELASTIC_APM_ACTIVATE=true
ELASTIC_APM_SERVICE_NAME="Skyworld POS"
ELASTIC_APM_SERVER_URL="http://172.10.10.10:8200"
CRON_MIDNIGHT="55 11 * * *"
CRON_EVERY_MINUTE="55 11 * * *"
CRON_EVERY_HOUR="0 * * * *"
EMAIL_HOST=smtp.gmail.com
EMAIL_POST=465
EMAIL_USER=weplayground.app@gmail.com
EMAIL_TOKEN="sonv vwiu khse vtmv"
MIDTRANS_URL=https://app.midtrans.com
MIDTRANS_PRODUCTION=true
MIDTRANS_SERVER_KEY=Mid-server-BZlPCcrWHDuSxW48oxBs5uAl
MIDTRANS_CLIENT_KEY=Mid-client-YhOPuo0NZPNZfiKq
EXPORT_LIMIT_PARTITION=200
ASSETS="https://asset.sky.eigen.co.id/"
GOOGLE_CALENDAR_KEY="AIzaSyCSg4P3uC9Z7kD1P4f3rf1BbBaz4Q-M55o"
GOOGLE_CALENDAR_ID="326464ac296874c7121825f5ef2e2799baa90b51da240f0045aae22beec10bd5@group.calendar.google.com"
SUPERSET_URL=https://dashboard.weplayground.eigen.co.id
SUPERSET_ADMIN_USERNAME=admin
SUPERSET_ADMIN_PASSWORD=admin
WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID=604883366037548
WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV

42
formula-readme.md Normal file
View File

@ -0,0 +1,42 @@
## Formula Calculation
### Instalation
```
yarn add mathjs algebra.js
```
### Example
```ts
import * as math from 'mathjs'
import { Equation, parse } from 'algebra.js'
const formula = 'dpp - (dpp*ppn) - (dpp*retribusi) - (dpp*service) - (dpp*ppn3)'
const total = '300000'
const variable = {
ppn: 11,
retribusi: 5000,
service: 5,
ppn3: 5000
}
try {
const x1 = math.simplify(formula, variable).toString()
console.log('Formula ', x1)
const dppFormula = parse(x1)
const totalFormula = parse(total)
const equation = new Equation(totalFormula, dppFormula)
console.log(equation.toString())
const result = equation.solveFor('dpp').toString()
console.log(result)
const value = math.evaluate(result)
console.log(value)
} catch (e) {
console.log(e)
}
```

View File

@ -17,26 +17,52 @@
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:cov": "jest --coverage", "test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json" "test:e2e": "jest --config ./test/jest-e2e.json",
"orm": "ts-node --project ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js -d ./src/database/ormconfig.ts",
"migration:execute": "yarn run orm migration:run",
"seed:config": "ts-node -r tsconfig-paths/register ./node_modules/typeorm-seeding/dist/cli.js -n ./src/database/seed-ormconfig.ts config",
"seed:run": "ts-node -r tsconfig-paths/register ./node_modules/typeorm-seeding/dist/cli.js -n ./src/database/seed-ormconfig.ts seed",
"factory:config": "ts-node -r tsconfig-paths/register ./node_modules/typeorm-seeding/dist/cli.js -n ./src/database/seed-data-ormconfig.ts config",
"factory:run": "ts-node -r tsconfig-paths/register ./node_modules/typeorm-seeding/dist/cli.js -n ./src/database/seed-data-ormconfig.ts seed",
"db:generate": "npm run orm migration:generate"
}, },
"dependencies": { "dependencies": {
"@faker-js/faker": "^8.4.1",
"@nestjs/axios": "^3.0.3",
"@nestjs/common": "^10.0.0", "@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.2", "@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.0.0", "@nestjs/core": "^10.0.0",
"@nestjs/cqrs": "^10.2.7", "@nestjs/cqrs": "^10.2.7",
"@nestjs/jwt": "^10.2.0", "@nestjs/jwt": "^10.2.0",
"@nestjs/platform-express": "^10.0.0", "@nestjs/platform-express": "^10.0.0",
"@nestjs/schedule": "^4.1.0",
"@nestjs/swagger": "^7.3.1", "@nestjs/swagger": "^7.3.1",
"@nestjs/typeorm": "^10.0.2", "@nestjs/typeorm": "^10.0.2",
"@types/multer": "^1.4.11",
"algebra.js": "^0.2.6",
"axios": "^1.7.5",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",
"dotenv": "^16.4.5",
"elastic-apm-node": "^4.5.4", "elastic-apm-node": "^4.5.4",
"exceljs": "^4.4.0",
"fs-extra": "^11.2.0",
"googleapis": "^140.0.0",
"gtts": "^0.2.1",
"handlebars": "^4.7.8",
"mathjs": "^13.0.2",
"midtrans-client": "^1.3.1",
"moment": "^2.30.1",
"nano": "^10.1.3", "nano": "^10.1.3",
"nodemailer": "^6.9.14",
"pdfmake": "^0.2.10",
"pg": "^8.11.5", "pg": "^8.11.5",
"plop": "^4.0.1", "plop": "^4.0.1",
"reflect-metadata": "^0.2.0", "reflect-metadata": "^0.2.0",
"rxjs": "^7.5.0", "rxjs": "^7.5.0",
"typeorm": "^0.3.20" "typeorm": "^0.3.20",
"typeorm-seeding": "^1.6.1"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^10.0.0", "@nestjs/cli": "^10.0.0",
@ -44,7 +70,7 @@
"@nestjs/testing": "^10.0.0", "@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/jest": "29.5.12", "@types/jest": "29.5.12",
"@types/node": "18.11.18", "@types/node": "^20.12.13",
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
@ -57,7 +83,7 @@
"supertest": "^6.1.3", "supertest": "^6.1.3",
"ts-jest": "29.0.3", "ts-jest": "29.0.3",
"ts-loader": "^9.2.3", "ts-loader": "^9.2.3",
"ts-node": "^10.0.0", "ts-node": "^10.9.2",
"tsconfig-paths": "4.1.1", "tsconfig-paths": "4.1.1",
"typescript": "^4.7.4" "typescript": "^4.7.4"
}, },

246
plopfile.js Normal file
View File

@ -0,0 +1,246 @@
const path = require('path');
const fs = require('fs');
module.exports = function (plop) {
plop.setGenerator('module', {
description: 'Create a new module by default',
prompts: [
{
type: 'input',
name: 'name',
message: 'Name: ',
validate: function (value) {
if (/.+/.test(value)) {
return true;
}
return 'Name is required';
},
},
{
type: 'list',
name: 'base',
message: 'Base: ',
choices: function () {
return ['base', 'base status', 'base core'];
},
},
{
type: 'list',
name: 'location',
message: 'Location: ',
choices: function () {
return ['item related', 'user related', 'season related', 'transaction', 'web information'];
},
},
],
actions: function (data) {
if (['base', 'base core'].includes(data.base)) data.orchestrator = 'data'
else if (data.base == 'base status') data.orchestrator = 'data transaction'
const destination = `src/modules/{{dashCase location}}/{{dashCase name}}`;
const result = [
...mappingModule(data.base, destination),
...mappingController(data.base, destination),
...mappingModel(data.base, destination),
...mappingService(destination),
...mappingOrchestrator(data.base, destination),
...mappingManager(data.base, destination)
]
return result
},
})
};
function mappingService(destination) {
const datas = [];
datas.push(
{
type: 'addMany',
destination: `${destination}/data/services`,
templateFiles: `src/core/templates/services/*.hbs`,
base: 'src/core/templates/services',
},
)
return datas;
}
function mappingOrchestrator(base, destination) {
const datas = [];
if (base == 'base status') {
datas.push(
{
type: 'addMany',
destination: `${destination}/domain/usecases`,
templateFiles: `src/core/templates/orchestrators/base-status/*.hbs`,
base: 'src/core/templates/orchestrators/base-status',
},
)
} else {
datas.push(
{
type: 'addMany',
destination: `${destination}/domain/usecases`,
templateFiles: `src/core/templates/orchestrators/base/*.hbs`,
base: 'src/core/templates/orchestrators/base',
},
)
}
datas.push(
{
type: 'addMany',
destination: `${destination}/domain/usecases`,
templateFiles: `src/core/templates/orchestrators/base-read/*.hbs`,
base: 'src/core/templates/orchestrators/base-read',
},
)
return datas;
}
function mappingController(base, destination) {
const datas = [];
if (base == 'base status') {
datas.push(
{
type: 'addMany',
destination: `${destination}/infrastructure`,
templateFiles: `src/core/templates/controllers/base-status/*.hbs`,
base: 'src/core/templates/controllers/base-status',
},
)
} else {
datas.push(
{
type: 'addMany',
destination: `${destination}/infrastructure`,
templateFiles: `src/core/templates/controllers/base/*.hbs`,
base: 'src/core/templates/controllers/base',
},
)
}
datas.push(
{
type: 'addMany',
destination: `${destination}/infrastructure`,
templateFiles: `src/core/templates/controllers/base-read/*.hbs`,
base: 'src/core/templates/controllers/base-read',
},
)
return datas;
}
function mappingModel(base, destination) {
const datas = [];
if (base == 'base status') {
datas.push(
{
type: 'addMany',
destination: `${destination}/domain/entities/event`,
templateFiles: `src/core/templates/events/base-status/*.hbs`,
base: 'src/core/templates/events/base-status',
}
)
}
datas.push(
{
type: 'addMany',
destination: `${destination}/data/models`,
templateFiles: `src/core/templates/models/*.hbs`,
base: 'src/core/templates/models',
},
{
type: 'addMany',
destination: `${destination}/domain/entities`,
templateFiles: `src/core/templates/entities/*.hbs`,
base: 'src/core/templates/entities',
},
{
type: 'addMany',
destination: `${destination}/infrastructure/dto`,
templateFiles: `src/core/templates/dtos/*.hbs`,
base: 'src/core/templates/dtos',
},
{
type: 'addMany',
destination: `${destination}/domain/entities/event`,
templateFiles: `src/core/templates/events/base/*.hbs`,
base: 'src/core/templates/events/base',
}
)
return datas;
}
function mappingModule(base, destination) {
const datas = [];
if (base == 'base status') {
datas.push(
{
type: 'addMany',
destination: destination,
templateFiles: `src/core/templates/modules/base-status/*.hbs`,
base: 'src/core/templates/modules/base-status',
}
)
} else {
datas.push(
{
type: 'addMany',
destination: destination,
templateFiles: `src/core/templates/modules/base/*.hbs`,
base: 'src/core/templates/modules/base',
}
)
}
datas.push(
{
type: 'addMany',
destination: destination,
templateFiles: `src/core/templates/modules/core/*.hbs`,
base: 'src/core/templates/modules/core',
}
)
return datas;
}
function mappingManager(base, destination) {
const datas = [];
const tujuan = `${destination}/domain/usecases/managers`;
if (base == 'base status') {
datas.push(
{
type: 'addMany',
destination: tujuan,
templateFiles: `src/core/templates/managers/manager-statuses/*.hbs`,
base: 'src/core/templates/managers/manager-statuses',
},
)
}
datas.push(
{
type: 'addMany',
destination: tujuan,
templateFiles: `src/core/templates/managers/base/*.hbs`,
base: 'src/core/templates/managers/base',
},
)
return datas;
}

View File

@ -1,7 +1,5 @@
import { Module, Scope } from '@nestjs/common'; import { Module, Scope } from '@nestjs/common';
import { RefreshTokenInterceptor, SessionModule } from './core/sessions'; import { RefreshTokenInterceptor, SessionModule } from './core/sessions';
import { AuthModule } from './auth/auth.module';
import { JWTGuard } from './core/guards';
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
import { HttpExceptionFilter, TransformInterceptor } from './core/response'; import { HttpExceptionFilter, TransformInterceptor } from './core/response';
import { ApmModule } from './core/apm'; import { ApmModule } from './core/apm';
@ -9,12 +7,96 @@ import { CONNECTION_NAME } from './core/strings/constants/base.constants';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { UserPrivilegeModule } from './modules/user-related/user-privilege/user-privilege.module'; import { UserPrivilegeModule } from './modules/user-related/user-privilege/user-privilege.module';
import { UserPrivilegeModel } from './modules/user-related/user-privilege/data/model/user-privilege.model';
import { CqrsModule } from '@nestjs/cqrs'; import { CqrsModule } from '@nestjs/cqrs';
import { CouchModule } from './modules/configuration/couch/couch.module'; import { CouchModule } from './modules/configuration/couch/couch.module';
import { UserPrivilegeModels } from './modules/user-related/user-privilege/constants';
import { RolesGuard } from './core/guards/domain/roles.guard';
import { PrivilegeService } from './core/guards/domain/services/privilege.service';
import { UserModel } from './modules/user-related/user/data/models/user.model';
import { AuthModule } from './modules/configuration/auth/auth.module';
import { UserModule } from './modules/user-related/user/user.module';
import { LogModel } from './modules/configuration/log/data/models/log.model';
import { ErrorLogModel } from './modules/configuration/log/data/models/error-log.model';
import { LogModule } from './modules/configuration/log/log.module';
import { TenantModule } from './modules/user-related/tenant/tenant.module';
import { ItemCategoryModule } from './modules/item-related/item-category/item-category.module';
import { ItemCategoryModel } from './modules/item-related/item-category/data/models/item-category.model';
import { ConstantModule } from './modules/configuration/constant/constant.module';
import { VipCategoryModule } from './modules/transaction/vip-category/vip-category.module';
import { VipCategoryModel } from './modules/transaction/vip-category/data/models/vip-category.model';
import { VipCodeModule } from './modules/transaction/vip-code/vip-code.module';
import { VipCodeModel } from './modules/transaction/vip-code/data/models/vip-code.model';
import { ItemModule } from './modules/item-related/item/item.module';
import { ItemModel } from './modules/item-related/item/data/models/item.model';
import { SeasonTypeModule } from './modules/season-related/season-type/season-type.module';
import { SeasonTypeModel } from './modules/season-related/season-type/data/models/season-type.model';
import { TaxModule } from './modules/transaction/tax/tax.module';
import { TaxModel } from './modules/transaction/tax/data/models/tax.model';
import { SalesPriceFormulaModule } from './modules/transaction/sales-price-formula/sales-price-formula.module';
import { SalesPriceFormulaModel } from './modules/transaction/sales-price-formula/data/models/sales-price-formula.model';
import { ProfitShareFormulaModule } from './modules/transaction/profit-share-formula/profit-share-formula.module';
import { PaymentMethodModule } from './modules/transaction/payment-method/payment-method.module';
import { PaymentMethodModel } from './modules/transaction/payment-method/data/models/payment-method.model';
import { SeasonPeriodModule } from './modules/season-related/season-period/season-period.module';
import { SeasonPeriodModel } from './modules/season-related/season-period/data/models/season-period.model';
import { ItemRateModule } from './modules/item-related/item-rate/item-rate.module';
import { ItemRateModel } from './modules/item-related/item-rate/data/models/item-rate.model';
import { GoogleCalendarModule } from './modules/configuration/google-calendar/google-calendar.module';
import { TransactionModule } from './modules/transaction/transaction/transaction.module';
import { TransactionModel } from './modules/transaction/transaction/data/models/transaction.model';
import {
TransactionBreakdownTaxModel,
TransactionItemBreakdownModel,
TransactionItemModel,
TransactionItemTaxModel,
} from './modules/transaction/transaction/data/models/transaction-item.model';
import { TransactionTaxModel } from './modules/transaction/transaction/data/models/transaction-tax.model';
import { ReconciliationModule } from './modules/transaction/reconciliation/reconciliation.module';
import { ReportModule } from './modules/reports/report/report.module';
import { ReportBookmarkModule } from './modules/reports/report-bookmark/report-bookmark.module';
import { ReportExportModule } from './modules/reports/report-export/report-export.module';
import { ReportBookmarkModel } from './modules/reports/shared/models/report-bookmark.model';
import { ExportReportHistoryModel } from './modules/reports/shared/models/export-report-history.model';
import { CronModule } from './modules/configuration/cron/cron.module';
import { MidtransModule } from './modules/configuration/midtrans/midtrans.module';
import { RefundModule } from './modules/transaction/refund/refund.module';
import { RefundModel } from './modules/transaction/refund/data/models/refund.model';
import { RefundItemModel } from './modules/transaction/refund/data/models/refund-item.model';
import { GateModule } from './modules/web-information/gate/gate.module';
import { GateModel } from './modules/web-information/gate/data/models/gate.model';
import { TermConditionModule } from './modules/web-information/term-condition/term-condition.module';
import { TermConditionModel } from './modules/web-information/term-condition/data/models/term-condition.model';
import { FaqModel } from './modules/web-information/faq/data/models/faq.model';
import { FaqModule } from './modules/web-information/faq/faq.module';
import { UploadModule } from './modules/configuration/upload/upload.module';
import { NewsModule } from './modules/web-information/news/news.module';
import { NewsModel } from './modules/web-information/news/data/models/news.model';
import { BannerModule } from './modules/web-information/banner/banner.module';
import { BannerModel } from './modules/web-information/banner/data/models/banner.model';
import { MailModule } from './modules/configuration/mail/mail.module';
import { PosLogModel } from './modules/configuration/log/data/models/pos-log.model';
import { ExportModule } from './modules/configuration/export/export.module';
import { TransactionDemographyModel } from './modules/transaction/transaction/data/models/transaction-demography.model';
import { SupersetModule } from './modules/configuration/superset/superset.module';
import { GateScanModule } from './modules/gates/gate.module';
import { UserLoginModel } from './modules/user-related/user/data/models/user-login.model';
import { LogUserLoginModel } from './modules/configuration/log/data/models/log-user-login.model';
import { AuthService } from './core/guards/domain/services/auth.service';
import { ReportSummaryModule } from './modules/reports/report-summary/report-summary.module';
import { QueueModule } from './modules/queue/queue.module';
import {
QueueOrderModel,
QueueTicketModel,
QueueItemModel,
QueueModel,
} from './modules/queue/data/models/queue.model';
import { ItemQueueModule } from './modules/item-related/item-queue/item-queue.module';
import { ItemQueueModel } from './modules/item-related/item-queue/data/models/item-queue.model';
import { QueueBucketModel } from './modules/queue/data/models/queue-bucket.model';
@Module({ @Module({
imports: [ imports: [
ApmModule.register(),
ConfigModule.forRoot({ ConfigModule.forRoot({
isGlobal: true, isGlobal: true,
}), }),
@ -27,19 +109,116 @@ import { CouchModule } from './modules/configuration/couch/couch.module';
password: process.env.DEFAULT_DB_PASS, password: process.env.DEFAULT_DB_PASS,
database: process.env.DEFAULT_DB_NAME, database: process.env.DEFAULT_DB_NAME,
entities: [ entities: [
UserPrivilegeModel, ...UserPrivilegeModels,
BannerModel,
ErrorLogModel,
FaqModel,
GateModel,
ItemModel,
ItemCategoryModel,
ItemRateModel,
ItemQueueModel,
LogModel,
LogUserLoginModel,
NewsModel,
PaymentMethodModel,
PosLogModel,
RefundModel,
RefundItemModel,
SalesPriceFormulaModel,
SeasonPeriodModel,
SeasonTypeModel,
TaxModel,
TermConditionModel,
TransactionModel,
TransactionItemModel,
TransactionTaxModel,
TransactionDemographyModel,
TransactionItemBreakdownModel,
TransactionItemTaxModel,
TransactionBreakdownTaxModel,
UserModel,
UserLoginModel,
VipCategoryModel,
VipCodeModel,
// report
ReportBookmarkModel,
ExportReportHistoryModel,
// Queue
QueueOrderModel,
QueueTicketModel,
QueueItemModel,
QueueModel,
QueueBucketModel,
], ],
synchronize: true, synchronize: false,
}), }),
CqrsModule,
SessionModule,
AuthModule, AuthModule,
ConstantModule,
CqrsModule,
CouchModule, CouchModule,
CronModule,
ExportModule,
GoogleCalendarModule,
LogModule,
MailModule,
MidtransModule,
SessionModule,
UploadModule,
// user
TenantModule,
UserModule,
UserPrivilegeModule, UserPrivilegeModule,
// Item
ItemCategoryModule,
ItemModule,
ItemRateModule,
ItemQueueModule,
// transaction
PaymentMethodModule,
ProfitShareFormulaModule,
ReconciliationModule,
RefundModule,
SalesPriceFormulaModule,
TaxModule,
TransactionModule,
VipCategoryModule,
VipCodeModule,
// session
SeasonTypeModule,
SeasonPeriodModule,
// web information
BannerModule,
FaqModule,
GateModule,
NewsModule,
TermConditionModule,
// report
ReportModule,
ReportBookmarkModule,
ReportExportModule,
ReportSummaryModule,
// superset
SupersetModule,
GateScanModule,
QueueModule,
], ],
controllers: [], controllers: [],
providers: [ providers: [
AuthService,
PrivilegeService,
/** /**
* By default all request from client will protect by JWT * By default all request from client will protect by JWT
* if there is some endpoint/function that does'nt require authentication * if there is some endpoint/function that does'nt require authentication
@ -48,7 +227,7 @@ import { CouchModule } from './modules/configuration/couch/couch.module';
{ {
provide: APP_GUARD, provide: APP_GUARD,
scope: Scope.REQUEST, scope: Scope.REQUEST,
useClass: JWTGuard, useClass: RolesGuard,
}, },
{ {
provide: APP_INTERCEPTOR, provide: APP_INTERCEPTOR,

View File

@ -1,10 +0,0 @@
import { Module } from '@nestjs/common';
import { AuthController } from './controllers/auth.controller';
import { UserDataService } from './data/user.dataservice';
import { AuthService } from './domain/services/auth.service';
@Module({
providers: [AuthService, UserDataService],
controllers: [AuthController],
})
export class AuthModule {}

View File

@ -1,32 +0,0 @@
import { Body, Controller, Get, Post } from '@nestjs/common';
import { Unprotected } from 'src/core/guards';
import { Pagination } from 'src/core/response';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { LoginRequest } from '../domain/entities/request.interface';
import { User } from '../domain/entities/user.interface';
import { AuthService } from '../domain/services/auth.service';
@Controller('auth')
export class AuthController {
constructor(private readonly service: AuthService) {}
@Unprotected()
@Post()
login(@Body() body: LoginRequest) {
return this.service.createAccessToken(body);
}
@Get()
user() {
return this.service.getUser();
}
@Pagination()
@Get('/all')
async users(): Promise<PaginationResponse<User>> {
return {
data: await this.service.getUsers(),
total: 101,
};
}
}

View File

@ -1,54 +0,0 @@
import { LoginRequest } from '../domain/entities/request.interface';
import { User } from '../domain/entities/user.interface';
const mockUsers: User[] = [
{
id: 1,
name: 'John Doe',
username: 'johndoe',
password: 'password1',
roles: ['admin'],
},
{
id: 2,
name: 'Jane Doe',
username: 'janedoe',
password: 'password2',
roles: ['user'],
},
{
id: 3,
name: 'Jim Brown',
username: 'jimbrown',
password: 'password3',
roles: ['user', 'admin'],
},
{
id: 4,
name: 'Jane Smith',
username: 'janesmith',
password: 'password4',
roles: ['user'],
},
{
id: 5,
name: 'John Smith',
username: 'johnsmith',
password: 'password5',
roles: ['admin'],
},
];
export class UserDataService {
async login({ username, password }: LoginRequest): Promise<User | undefined> {
const user = mockUsers.find((user) => {
return user.username == username && user.password == password;
});
return user;
}
async users(): Promise<User[]> {
return mockUsers;
}
}

View File

@ -1,7 +0,0 @@
export interface User {
id: number;
name: string;
username: string;
password: string;
roles: string[];
}

View File

@ -1,18 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();
service = module.get<AuthService>(AuthService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -1,37 +0,0 @@
import { Injectable, UnprocessableEntityException } from '@nestjs/common';
import { SessionService, UserProvider, UsersSession } from 'src/core/sessions';
import { UserDataService } from '../../data/user.dataservice';
import { LoginRequest } from '../entities/request.interface';
import { User } from '../entities/user.interface';
@Injectable()
export class AuthService {
constructor(
private readonly userDataService: UserDataService,
private readonly session: SessionService,
private readonly user: UserProvider,
) {}
async createAccessToken(payload: LoginRequest): Promise<string> {
const user = await this.userDataService.login(payload);
if (!user)
throw new UnprocessableEntityException(`Username or Password not match`);
const token = this.session.createAccessToken({
id: user.id,
// username: user.username,
name: user.name,
// roles: user.roles,
});
return token;
}
getUser(): UsersSession {
return this.user.user;
}
async getUsers(): Promise<User[]> {
return this.userDataService.users();
}
}

View File

@ -1 +1,3 @@
export const UNPROTECTED_URL = 'unprotected_url'; export const UNPROTECTED_URL = 'unprotected_url';
export const PRIVILEGE_KEY = 'privilege_key';
export const MAIN_MENU = 'main_menu';

View File

@ -1,7 +1,9 @@
import { SetMetadata } from '@nestjs/common'; import { SetMetadata } from '@nestjs/common';
import { UNPROTECTED_URL } from '../../constants'; import { MAIN_MENU, UNPROTECTED_URL } from '../../constants';
/** /**
* @deprecated
* Use Public instead
* This decorator will exclude the request from token check * This decorator will exclude the request from token check
* *
* NOTE: * NOTE:
@ -11,3 +13,9 @@ import { UNPROTECTED_URL } from '../../constants';
*/ */
export const Unprotected = (isUnprotected = true) => export const Unprotected = (isUnprotected = true) =>
SetMetadata(UNPROTECTED_URL, isUnprotected); SetMetadata(UNPROTECTED_URL, isUnprotected);
export const Public = (isUnprotected = true) =>
SetMetadata(UNPROTECTED_URL, isUnprotected);
export const MainMenu = () => SetMetadata(MAIN_MENU, true);
export const ExcludePrivilege = () => SetMetadata(MAIN_MENU, true);

View File

@ -2,27 +2,29 @@ import {
Injectable, Injectable,
CanActivate, CanActivate,
ExecutionContext, ExecutionContext,
UnauthorizedException,
Scope, Scope,
Logger, Logger,
UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { SessionService, UsersSession } from 'src/core/sessions'; import { SessionService, UsersSession } from 'src/core/sessions';
import { UNPROTECTED_URL } from '../constants'; import { UNPROTECTED_URL } from '../constants';
import { PrivilegeService } from './services/privilege.service';
import { AuthService } from './services/auth.service';
@Injectable({ scope: Scope.REQUEST }) @Injectable({ scope: Scope.REQUEST })
export class JWTGuard implements CanActivate { export class JWTGuard implements CanActivate {
constructor( constructor(
protected readonly session: SessionService, protected readonly session: SessionService,
protected readonly reflector: Reflector, protected readonly reflector: Reflector,
protected readonly privilege: PrivilegeService,
protected readonly authService: AuthService,
) {} ) {}
protected isPublic = false;
protected userSession: UsersSession; protected userSession: UsersSession;
canActivate( async canActivate(context: ExecutionContext) {
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
/** /**
* Check if access url is protected or not * Check if access url is protected or not
* By default `isUnprotected` equals `false` * By default `isUnprotected` equals `false`
@ -31,6 +33,8 @@ export class JWTGuard implements CanActivate {
UNPROTECTED_URL, UNPROTECTED_URL,
[context.getHandler(), context.getClass()], [context.getHandler(), context.getClass()],
); );
this.isPublic = isUnprotected;
this.session.setPublic(isUnprotected);
if (isUnprotected) return true; if (isUnprotected) return true;
/** /**
@ -56,9 +60,29 @@ export class JWTGuard implements CanActivate {
*/ */
try { try {
this.userSession = this.session.verifyToken(token); this.userSession = this.session.verifyToken(token);
await this.authService.verifyRegisteredLoginToken(token);
Logger.log(`Access from ${this.userSession.name}`, 'AuthGuard'); Logger.log(`Access from ${this.userSession.name}`, 'AuthGuard');
return true; return true;
} catch (error) { } catch (error) {
const expiredError = error.message;
if (expiredError === 'jwt expired') {
const [, body] = token.split('.');
const bodyToken = JSON.parse(atob(body));
const user = {
role: bodyToken.role,
user_id: bodyToken.id,
username: bodyToken.username,
user_privilege_id: bodyToken.user_privilege_id,
item_id: bodyToken.item_id,
item_name: bodyToken.item_name,
source: bodyToken.source,
};
this.authService.logoutUser(user, token);
}
throw new UnauthorizedException({ throw new UnauthorizedException({
code: 10001, code: 10001,
message: message:

View File

@ -1,23 +1,36 @@
import { Injectable, ExecutionContext } from '@nestjs/common'; import {
import { Observable } from 'rxjs'; Injectable,
ExecutionContext,
ForbiddenException,
} from '@nestjs/common';
import { JWTGuard } from './jwt.guard'; import { JWTGuard } from './jwt.guard';
import { MAIN_MENU } from '../constants';
@Injectable() @Injectable()
export class RolesGuard extends JWTGuard { export class RolesGuard extends JWTGuard {
canActivate( async canActivate(context: ExecutionContext): Promise<boolean> {
context: ExecutionContext, await super.canActivate(context);
): boolean | Promise<boolean> | Observable<boolean> {
super.canActivate(context);
/** // jika endpoint tersebut bukan public, maka lakukan check lanjutan
* Create function to check if `this.userSession` have access if (!this.isPublic) {
* to Read / Create / Update / and Other Action // Check apakah endpoint ada decorator untuk exlude privilege (@ExcludePrivilege())
*/ const excludePrivilege = this.reflector.getAllAndOverride<boolean>(
MAIN_MENU,
[context.getHandler(), context.getClass()],
);
if (excludePrivilege) return true;
// check apakah dapat akses module
const isNotAllow = await this.privilege.isNotAllowed();
if (isNotAllow) {
throw new ForbiddenException({
statusCode: 10003,
message: `Akses Terlarang, anda tidak punya akses ke module ini!`,
error: 'ACCESS_FORBIDDEN',
});
}
}
/**
* Assign rules to session, So Query can take the rules and give
* the data base on user request
*/
return true; return true;
} }
} }

View File

@ -0,0 +1,78 @@
import {
HttpStatus,
Injectable,
Scope,
UnauthorizedException,
} from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import {
CONNECTION_NAME,
OPERATION,
} from 'src/core/strings/constants/base.constants';
import { DataSource } from 'typeorm';
import { UserRole } from 'src/modules/user-related/user/constants';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { EventBus } from '@nestjs/cqrs';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
interface UserEntity {
user_id: string;
username: string;
role: UserRole;
user_privilege_id: string;
item_id: string;
item_name: string;
source: AppSource;
}
@Injectable({ scope: Scope.REQUEST })
export class AuthService {
constructor(
@InjectDataSource(CONNECTION_NAME.DEFAULT)
protected readonly dataSource: DataSource,
private eventBus: EventBus,
) {}
get repository() {
return this.dataSource.getRepository(UserLoginModel);
}
async logoutUser(user: UserEntity, token: string) {
await this.repository.delete({ login_token: token });
const userLogout = {
type: LogUserType.logout,
created_at: new Date().getTime(),
name: user.username,
user_privilege_id: user.user_privilege_id,
...user,
};
this.eventBus.publish(
new LogUserLoginEvent({
id: user.user_id,
old: null,
data: userLogout,
user: userLogout as any,
description: 'Logout',
module: UserModel.name,
op: OPERATION.UPDATE,
}),
);
}
async verifyRegisteredLoginToken(token: string) {
const data = await this.repository.findOneBy({ login_token: token });
if (!data) {
throw new UnauthorizedException({
statusCode: HttpStatus.UNAUTHORIZED,
message: `Invalid token`,
error: 'Unauthorized',
});
}
}
}

View File

@ -0,0 +1,74 @@
import { ForbiddenException, Inject, Injectable, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { InjectDataSource } from '@nestjs/typeorm';
import { getAction } from 'src/core/helpers/path/get-action-from-path.helper';
import { UserProvider } from 'src/core/sessions';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { UserPrivilegeConfigurationModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege-configuration.model';
import { DataSource, IsNull } from 'typeorm';
import { UserRole } from 'src/modules/user-related/user/constants';
import { UserPrivilegeConfigurationEntity } from 'src/modules/user-related/user-privilege/domain/entities/user-privilege-configuration.entity';
@Injectable({ scope: Scope.REQUEST })
export class PrivilegeService {
constructor(
@InjectDataSource(CONNECTION_NAME.DEFAULT)
protected readonly dataSource: DataSource,
@Inject(REQUEST) private readonly request: Request,
protected readonly session: UserProvider,
) {}
get repository() {
return this.dataSource.getRepository(UserPrivilegeConfigurationModel);
}
get user() {
return this.session.user;
}
get action() {
const headerAction = this.request.headers['ex-model-action'] as string;
return headerAction ?? getAction(this.request.method, this.request.path);
}
async isAllowed() {
// jika rolenya adalah superadmin, abaikan dan return true
if (this.user.role == UserRole.SUPERADMIN) return true;
// check privilege dan sesuaikan dengan akse
const configurations = await this.privilegeConfiguration();
return configurations[this.action];
}
async isNotAllowed() {
return !(await this.isAllowed());
}
private moduleKey() {
const headerKey = 'ex-model-key';
const moduleKey = this.request.headers[headerKey] as string;
if (!moduleKey) {
throw new ForbiddenException({
statusCode: 10005,
message: `Akses Terlarang, anda tidak punya akses ke module ini!`,
error: 'MODULE_KEY_NOT_FOUND',
});
}
const [module, menu, sub_menu, section] = moduleKey.split('.');
return { module, menu, sub_menu, section };
}
async privilegeConfiguration(): Promise<UserPrivilegeConfigurationEntity> {
const { module, menu } = this.moduleKey();
return await this.repository.findOne({
select: ['id', 'view', 'create', 'edit', 'delete', 'cancel', 'confirm'],
where: {
user_privilege_id: this.user.user_privilege_id,
module: module,
menu: menu ?? IsNull(),
},
});
}
}

View File

@ -0,0 +1,11 @@
export enum LogUserType {
login = 'login',
logout = 'logout',
}
export enum AppSource {
POS_ADMIN = 'POS_ADMIN',
POS_COUNTER = 'POS_COUNTER',
QUEUE_ADMIN = 'QUEUE_ADMIN',
QUEUE_CUSTOMER = 'QUEUE_CUSTOMER',
}

View File

@ -0,0 +1,17 @@
import { compare, hash } from 'bcrypt';
export async function hashPassword(
password: string,
saltRounds: number,
): Promise<string> {
const hashedPassword = await hash(password, 10);
return hashedPassword;
}
export async function validatePassword(
password: string,
hashedPassword: string,
): Promise<boolean> {
const isPasswordValid = await compare(password, hashedPassword);
return isPasswordValid;
}

View File

@ -0,0 +1,28 @@
import { PrivilegeAction } from 'src/core/strings/constants/privilege.constants';
function containsUuid(str) {
const parts = str.split('/'); // Split the string by "/"
for (const part of parts) {
if (
/^[0-9a-f]{8}\b-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
part,
)
) {
return true;
}
}
return false;
}
export function getAction(method: string, path: string): string {
if (method === 'GET') return PrivilegeAction.VIEW;
else if (method === 'POST') return PrivilegeAction.CREATE;
else if (method === 'DELETE') return PrivilegeAction.DELETE;
else if (method === 'PATCH' || method === 'PUT') {
if (['confirm', 'active', 'inactive'].includes(path))
return PrivilegeAction.CONFIRM;
else if (path.includes('cancel')) return PrivilegeAction.CANCEL;
else return PrivilegeAction.EDIT;
}
return 'forbidden';
}

View File

@ -0,0 +1,28 @@
import * as fs from 'fs-extra';
import * as path from 'path';
export async function MoveFilePathHelper(data) {
const imagePath = data['qr_image'] ?? data['image_url'];
const sourcePath = path.join(__dirname, '../../../../uploads/', imagePath);
const movePath =
'data/' +
imagePath
.split('/')
.filter((item) => !['uploads', 'tmp'].includes(item))
.join('/');
const destinationPath = path.join(
__dirname,
'../../../../uploads/',
movePath,
);
try {
await fs.move(sourcePath, destinationPath);
Object.assign(data, {
image_url: movePath,
});
} catch (error) {
console.log(`Failed! Error move file data`);
}
}

View File

@ -0,0 +1,46 @@
import { extname } from 'path';
import { v4 as uuidv4 } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
import * as fs from 'fs';
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
import { diskStorage } from 'multer';
const MB = 1024 * 1024;
const fileFilter = (req, file, callback) => {
if (
file.mimetype.match(/\/(jpg|jpeg|png|flv|mp4|m3u8|ts|3gp|mov|avi|wmv)$/)
) {
callback(null, true);
} else {
callback(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST,
),
false,
);
}
};
const editFileName = (req, file, callback) => {
const fileExtName = extname(file.originalname);
const randomName = uuidv4();
callback(null, `${randomName}${fileExtName}`);
};
const destinationPath = (req, file, cb) => {
let modulePath = req.body.module;
if (req.body.sub_module) modulePath = `${modulePath}/${req.body.sub_module}`;
fs.mkdirSync(`./uploads/tmp/${modulePath}`, { recursive: true });
cb(null, `./uploads/tmp/${modulePath}`);
};
export const StoreFileConfig: MulterOptions = {
storage: diskStorage({
destination: destinationPath,
filename: editFileName,
}),
fileFilter: fileFilter,
};

View File

@ -0,0 +1,22 @@
import { SelectQueryBuilder } from 'typeorm';
export class BetweenQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected from: any,
protected to: any,
protected valueAlias: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} BETWEEN :from${this.valueAlias} AND :to${this.valueAlias}`,
{
[`from${this.valueAlias}`]: this.from,
[`to${this.valueAlias}`]: this.to,
},
);
}
}

View File

@ -0,0 +1,54 @@
import { HttpStatus, UnprocessableEntityException } from '@nestjs/common';
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
import { columnUniques } from 'src/core/strings/constants/interface.constants';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
export class CheckDuplicateHelper {
constructor(
private dataService: BaseDataService<any>,
private tableName: TABLE_NAME,
private duplicateColumn: columnUniques[],
private entity: any,
private entityId?: string,
) {}
async execute() {
for (const columnCheck of this.duplicateColumn) {
const queryBuilder = this.dataService
.getRepository()
.createQueryBuilder(this.tableName);
// process pengecekan column
queryBuilder.where(
`replace(trim(lower(${this.tableName}.${columnCheck.column})), ' ',' ') = :query`,
{
query: this.entity[columnCheck.column]
?.toLowerCase()
.trim()
.replace(/ +(?= )/g, ''),
},
);
// jika ingin check specific data
if (columnCheck.query) {
queryBuilder.andWhere(columnCheck.query);
}
// jika update, akan membawa id. Maka dari itu, jangan validasi diri sendiri
if (this.entityId) {
queryBuilder.andWhere(`id Not In ('${this.entityId}')`);
}
const data_exists = await queryBuilder.getCount();
if (data_exists > 0) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! Data dengan ${columnCheck.column} : ${
this.entity[columnCheck.column]
} telah ada`,
error: 'Unprocessable Entity',
});
}
}
}
}

View File

@ -0,0 +1,87 @@
import { Brackets, SelectQueryBuilder } from 'typeorm';
import { WhereInQueryHelper } from './or-where-in-query.helpe';
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
import { BetweenQueryHelper } from './between-query.helper';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { ORDER_TYPE, STATUS } from 'src/core/strings/constants/base.constants';
export function setQueryFilterDefault(
queryBuilder: SelectQueryBuilder<any>,
baseFilter: BaseFilterEntity,
tableName: TABLE_NAME,
): SelectQueryBuilder<any> {
// filter berdasarkan id pembuat
if (!!baseFilter.created_ids)
new WhereInQueryHelper(
queryBuilder,
tableName,
'creator_id',
baseFilter.created_ids,
'creator_ids',
).getQuery();
// filter berdasarkan tanggal terakhir dibuat
if (!!baseFilter.created_from && !!baseFilter.created_to)
new BetweenQueryHelper(
queryBuilder,
tableName,
'created_at',
baseFilter.created_from,
baseFilter.created_to,
'created',
).getQuery();
// filter berdasarkan id pengubah
if (!!baseFilter.updated_ids)
new WhereInQueryHelper(
queryBuilder,
tableName,
'editor_id',
baseFilter.updated_ids,
'editor_ids',
).getQuery();
// filter berdasarkan tanggal terakhir update
if (!!baseFilter.updated_from && !!baseFilter.updated_to)
new BetweenQueryHelper(
queryBuilder,
tableName,
'updated_at',
baseFilter.updated_from,
baseFilter.updated_to,
'updated',
).getQuery();
return queryBuilder;
}
export function getOrderBy(
baseFilter: BaseFilterEntity,
queryBuilder: SelectQueryBuilder<any>,
tableName: TABLE_NAME,
) {
let orderBys: string[] = [`${tableName}.created_at`];
const orderType = baseFilter.order_type ?? ORDER_TYPE.DESC;
if (!!baseFilter.order_by) {
orderBys =
baseFilter.order_by.split('.').length > 1
? [`${baseFilter.order_by}`]
: [`${tableName}.${baseFilter.order_by}`];
if (
baseFilter.order_by.split('.').length == 1 &&
baseFilter.order_by.split('.').pop() != 'id'
) {
orderBys.push(`${tableName}.created_at`);
}
}
for (let i = 0; i < orderBys.length; i++) {
if (i == 0) {
queryBuilder.orderBy(orderBys[i], orderType);
} else {
queryBuilder.addOrderBy(orderBys[i], orderType);
}
}
}

View File

@ -0,0 +1,31 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { SelectQueryBuilder } from 'typeorm';
export function joinRelationHelper(
relations: string[],
tableName: TABLE_NAME,
queryBuilder: SelectQueryBuilder<any>,
type?: string,
) {
relations.forEach((relation) => {
let alias = relation;
let relationName = `${tableName}.${relation}`;
if (relation.split(' ').length > 1) {
alias = relation.split(' ').pop();
const relationpath = relation.split(' ')[0];
if (relationpath.split('.').length > 1) relationName = relationpath;
else relationName = `${tableName}.${relation.split(' ')[0]}`;
} else if (relation.split('.').length > 1) {
alias = relation.split('.').pop();
relationName = relation;
}
if (type == 'count')
queryBuilder.loadRelationCountAndMap(relationName, relationName, alias);
else if (type == 'select')
queryBuilder.leftJoinAndSelect(relationName, alias);
else queryBuilder.leftJoin(relationName, alias);
});
}

View File

@ -0,0 +1,20 @@
import { SelectQueryBuilder } from 'typeorm';
export class WhereInQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected values: string[],
protected valueAliases: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} IN (:...${this.valueAliases})`,
{
[this.valueAliases]: this.values,
},
);
}
}

View File

@ -0,0 +1,20 @@
import { SelectQueryBuilder } from 'typeorm';
export class SearchQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected value: string,
protected valueAliases: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} ILIKE :${this.valueAliases}`,
{
[this.valueAliases]: `%${this.value}%`,
},
);
}
}

View File

@ -1,12 +1,6 @@
import { Param } from 'src/core/modules/domain/entities/base-filter.entity';
import { Brackets, SelectQueryBuilder } from 'typeorm'; import { Brackets, SelectQueryBuilder } from 'typeorm';
export interface Param {
cols: string;
data: string[];
additional?: any[];
leftJoin?: any[];
}
export class SpecificSearchFilter<Entity = any> { export class SpecificSearchFilter<Entity = any> {
constructor( constructor(
private query: SelectQueryBuilder<Entity>, private query: SelectQueryBuilder<Entity>,
@ -26,12 +20,16 @@ export class SpecificSearchFilter<Entity = any> {
new Brackets((qb) => { new Brackets((qb) => {
params.forEach((param) => { params.forEach((param) => {
const { cols, data, additional, leftJoin } = param; const { cols, data, additional, leftJoin } = param;
const columns = cols.split('.');
let arr = data;
const arr = data?.map((el) => if (!columns.includes('status::text')) {
el.includes("'") arr = data?.map((el) =>
? `'%${el.trim().replace(/'/g, "''").replace(/\s+/g, ' ')}%'` el.includes("'")
: `'%${el.trim().replace(/\s+/g, ' ')}%'`, ? `'%${el.trim().replace(/'/g, "''").replace(/\s+/g, ' ')}%'`
); : `'%${el.trim().replace(/\s+/g, ' ')}%'`,
);
}
const aliases = !cols.match(/\./g) const aliases = !cols.match(/\./g)
? this.table.concat(`.${cols}`) ? this.table.concat(`.${cols}`)

View File

@ -0,0 +1,83 @@
import { Injectable, UnprocessableEntityException } from '@nestjs/common';
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
import { validateRelations } from 'src/core/strings/constants/interface.constants';
@Injectable()
export class ValidateRelationHelper<Entity> {
constructor(
private dataId: string,
private dataService: BaseDataService<Entity>,
private relations: validateRelations[],
private tableName: string,
) {}
async execute() {
const repository = this.dataService.getRepository();
const queryBuilder = repository.createQueryBuilder(this.tableName);
// load relation
for (const relation of this.relations) {
if (relation.singleQuery) {
queryBuilder.leftJoinAndMapOne(
`${this.tableName}.${relation.relation}`,
`${this.tableName}.${relation.relation}`,
relation.relation,
);
} else if (relation.query) {
queryBuilder.loadRelationCountAndMap(
`${this.tableName}.total_${relation.relation}`,
`${this.tableName}.${relation.relation}`,
`total_${relation.relation}`,
relation.query,
);
} else {
queryBuilder.loadRelationCountAndMap(
`${this.tableName}.total_${relation.relation}`,
`${this.tableName}.${relation.relation}`,
`total_${relation.relation}`,
);
}
}
// filtering data only with specific data
queryBuilder.where(`${this.tableName}.id in ('${this.dataId}')`);
// get data
const data = await queryBuilder.getOne();
// process validasi
for (const relation of this.relations) {
const message =
relation.message ??
`Failed! this data already connected to ${relation.relation}`;
if (relation.singleQuery) {
const relationColumn =
data[relation.relation]?.[`${relation.singleQuery[0]}`];
if (
!!relationColumn &&
this.mappingValidator(
relationColumn,
relation.singleQuery[1],
relation.singleQuery[2],
)
)
throw new UnprocessableEntityException(message);
} else if (data[`total_${relation.relation}`] > 0)
throw new UnprocessableEntityException(message);
}
}
mappingValidator(column, operator, value) {
switch (operator) {
case '!=':
return column != value;
case '==':
return column == value;
default:
return column == value;
}
}
}

View File

@ -1,5 +1,5 @@
import { Entity, PrimaryGeneratedColumn } from "typeorm"; import { Entity, PrimaryGeneratedColumn } from 'typeorm';
import { BaseCoreEntity } from "../../domain/entities/base-core.entity"; import { BaseCoreEntity } from '../../domain/entities/base-core.entity';
@Entity() @Entity()
export abstract class BaseCoreModel<Entity> implements BaseCoreEntity { export abstract class BaseCoreModel<Entity> implements BaseCoreEntity {

View File

@ -1,10 +1,13 @@
import { Column, Entity } from "typeorm"; import { Column, Entity } from 'typeorm';
import { BaseModel } from "./base.model"; import { BaseModel } from './base.model';
import { STATUS } from "src/core/strings/constants/base.constants"; import { STATUS } from 'src/core/strings/constants/base.constants';
import { BaseStatusEntity } from "../../domain/entities/base-status.entity"; import { BaseStatusEntity } from '../../domain/entities/base-status.entity';
@Entity() @Entity()
export abstract class BaseStatusModel<Entity> extends BaseModel<Entity> implements BaseStatusEntity { export abstract class BaseStatusModel<Entity>
extends BaseModel<Entity>
implements BaseStatusEntity
{
@Column('enum', { name: 'status', enum: STATUS, default: STATUS.DRAFT }) @Column('enum', { name: 'status', enum: STATUS, default: STATUS.DRAFT })
status: STATUS; status: STATUS;
} }

View File

@ -3,7 +3,10 @@ import { BaseCoreModel } from './base-core.model';
import { BaseEntity } from '../../domain/entities/base.entity'; import { BaseEntity } from '../../domain/entities/base.entity';
@Entity() @Entity()
export abstract class BaseModel<Entity> extends BaseCoreModel<Entity> implements BaseEntity { export abstract class BaseModel<Entity>
extends BaseCoreModel<Entity>
implements BaseEntity
{
@Column('varchar', { name: 'creator_id', length: 36, nullable: true }) @Column('varchar', { name: 'creator_id', length: 36, nullable: true })
creator_id: string; creator_id: string;
@ -19,6 +22,6 @@ export abstract class BaseModel<Entity> extends BaseCoreModel<Entity> implements
@Column({ type: 'bigint', nullable: false }) @Column({ type: 'bigint', nullable: false })
created_at: number; created_at: number;
@Column({ type: 'bigint', nullable: false }) @Column({ type: 'bigint', nullable: false })
updated_at: number; updated_at: number;
} }

View File

@ -1,54 +1,89 @@
import { EntityTarget, FindManyOptions, QueryRunner, Repository } from "typeorm"; import {
EntityTarget,
FindManyOptions,
QueryRunner,
Repository,
} from 'typeorm';
export abstract class BaseDataService<Entity> { export abstract class BaseDataService<Entity> {
constructor(private repository: Repository<Entity>) {}
constructor(private repository: Repository<Entity>) {}
getRepository(): Repository<Entity> { getRepository(): Repository<Entity> {
return this.repository; return this.repository;
} }
async create( async create(
queryRunner: QueryRunner, queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>, entityTarget: EntityTarget<Entity>,
entity: Entity, entity: Entity,
): Promise<Entity> { ): Promise<Entity> {
const newEntity = queryRunner.manager.create(entityTarget, entity); // const newEntity = this.repository.create(entityTarget, entity);
return await queryRunner.manager.save(newEntity); return await this.repository.save(entity);
} }
async update(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
filterUpdate: any,
entity: Entity,
): Promise<Entity> {
const newEntity = await queryRunner.manager.findOne(entityTarget, {
where: filterUpdate,
});
if (!newEntity) throw new Error('Data not found!'); async createMany(
Object.assign(newEntity, entity); queryRunner: QueryRunner,
return await queryRunner.manager.save(newEntity); entityTarget: EntityTarget<Entity>,
} entity: Entity[],
): Promise<Entity[]> {
// const newEntity = this.repository.create(entityTarget, entity);
return await this.repository.save(entity);
}
async deleteById( async createBatch(
queryRunner: QueryRunner, queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>, entityTarget: EntityTarget<Entity>,
id: string, entity: Entity[],
): Promise<void> { ): Promise<Entity[]> {
await queryRunner.manager.delete(entityTarget, { id }); // const newEntity = this.repository.create(entityTarget, entity);
} return await this.repository.save(entity);
}
async deleteByOptions( async update(
queryRunner: QueryRunner, queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>, entityTarget: EntityTarget<Entity>,
findManyOptions: FindManyOptions<Entity>, filterUpdate: any,
): Promise<void> { entity: Entity,
await queryRunner.manager.delete(entityTarget, findManyOptions); ): Promise<Entity> {
} const newEntity = await this.repository.findOne({
where: filterUpdate,
});
async getOneByOptions(findOneOptions): Promise<Entity> { if (!newEntity) throw new Error('Data not found!');
return await this.repository.findOne(findOneOptions); Object.assign(newEntity, entity);
} return await this.repository.save(newEntity);
} }
async deleteById(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
id: string,
): Promise<void> {
await this.repository.delete(id);
}
async deleteByIds(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
ids: string[],
): Promise<void> {
await this.repository.delete(ids);
}
async deleteByOptions(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
findManyOptions: FindManyOptions<Entity>,
): Promise<void> {
const datas = await this.repository.find(findManyOptions);
await this.repository.delete(datas?.map((item) => item['id']));
}
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
async getManyByOptions(findOneOptions): Promise<Entity[]> {
return await this.repository.find(findOneOptions);
}
}

View File

@ -1,42 +1,42 @@
import { FindOneOptions, Repository, SelectQueryBuilder } from "typeorm"; import { FindOneOptions, Repository, SelectQueryBuilder } from 'typeorm';
import { BaseFilterEntity } from "../../domain/entities/base-filter.entity"; import { BaseFilterEntity } from '../../domain/entities/base-filter.entity';
import { PaginationResponse } from "src/core/response/domain/ok-response.interface"; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
export abstract class BaseReadService<Entity> { export abstract class BaseReadService<Entity> {
constructor(private repository: Repository<Entity>) {}
constructor(private repository: Repository<Entity>) {}
getRepository(): Repository<Entity> { getRepository(): Repository<Entity> {
return this.repository; return this.repository;
} }
async getIndex( async getIndex(
queryBuilder: SelectQueryBuilder<Entity>, queryBuilder: SelectQueryBuilder<Entity>,
params: BaseFilterEntity, params: BaseFilterEntity,
): Promise<PaginationResponse<Entity>> { ): Promise<PaginationResponse<Entity>> {
const [data, total] = await queryBuilder const limit = params.limit ?? 10;
.take(+params.limit) const page = params.page ?? 1;
.skip(+params.limit * +params.page - +params.limit) const [data, total] = await queryBuilder
.getManyAndCount(); .take(+limit)
.skip(+limit * +page - +limit)
.getManyAndCount();
return { return {
data, data,
total, total,
}; };
} }
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
async getOneOrFailByOptions(
findOneOptions: FindOneOptions<Entity>,
): Promise<Entity> {
return await this.repository.findOneOrFail(findOneOptions);
}
async getManyByOptions(findManyOptions): Promise<Entity[]> {
return await this.repository.find(findManyOptions);
}
} async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
async getOneOrFailByOptions(
findOneOptions: FindOneOptions<Entity>,
): Promise<Entity> {
return await this.repository.findOneOrFail(findOneOptions);
}
async getManyByOptions(findManyOptions): Promise<Entity[]> {
return await this.repository.find(findManyOptions);
}
}

View File

@ -1,52 +1,41 @@
import { Repository, TreeRepository } from "typeorm"; import { Repository, TreeRepository } from 'typeorm';
import { BaseReadService } from "./base-read.service"; import { BaseReadService } from './base-read.service';
export abstract class BaseTreeReadService<Entity> extends BaseReadService<Entity> { export abstract class BaseTreeReadService<
Entity,
constructor( > extends BaseReadService<Entity> {
private dataRepository: Repository<Entity>, constructor(
private treeRepository: TreeRepository<Entity> private dataRepository: Repository<Entity>,
) { private treeRepository: TreeRepository<Entity>,
super(dataRepository); ) {
} super(dataRepository);
}
async findRoots() { async findRoots() {
return this.treeRepository.findRoots() return this.treeRepository.findRoots();
} }
async findDescendants( async findDescendants(parent, relations = []): Promise<Entity[]> {
parent, return this.treeRepository.findDescendants(parent, {
relations = [], relations: relations,
): Promise<Entity[]> {
return this.treeRepository.findDescendants(parent, {
relations: relations,
});
}
async findDescendantsTree(
parent,
relations = [],
): Promise<Entity> {
return this.treeRepository.findDescendantsTree(parent, {
relations: relations,
});
}
async findAncestors(
parent,
relations = [],
): Promise<Entity[]> {
return await this.treeRepository.findAncestors(parent, {
relations: relations,
}); });
} }
async findAncestorsTree( async findDescendantsTree(parent, relations = []): Promise<Entity> {
parent, return this.treeRepository.findDescendantsTree(parent, {
relations = [], relations: relations,
): Promise<Entity> {
return await this.treeRepository.findAncestorsTree(parent, {
relations: relations,
}); });
} }
}
async findAncestors(parent, relations = []): Promise<Entity[]> {
return await this.treeRepository.findAncestors(parent, {
relations: relations,
});
}
async findAncestorsTree(parent, relations = []): Promise<Entity> {
return await this.treeRepository.findAncestorsTree(parent, {
relations: relations,
});
}
}

View File

@ -1,3 +1,3 @@
export interface BaseCoreEntity { export interface BaseCoreEntity {
id: string; id?: string;
} }

View File

@ -1,18 +1,32 @@
import { ORDER_TYPE, STATUS } from "src/core/strings/constants/base.constants"; import { ORDER_TYPE, STATUS } from 'src/core/strings/constants/base.constants';
export interface BaseFilterEntity { export interface BaseFilterEntity {
page: number; page: number;
limit: number; limit: number;
q?: string; q?: string;
names: string[]; names: string[];
entity_ids: string[]; entity_ids: string[];
order_by: string; order_by: string;
order_type: ORDER_TYPE; order_type: ORDER_TYPE;
statuses: STATUS[]; statuses: STATUS[];
created_ids: string[]; created_ids: string[];
created_from: number; created_from: number;
created_to: number; created_to: number;
updated_ids: string[]; updated_ids: string[];
updated_from: number; updated_from: number;
updated_to: number; updated_to: number;
} }
export interface Param {
cols: string;
data: string[];
additional?: any[];
leftJoin?: any[];
isStatus?: boolean;
}
export interface RelationParam {
joinRelations: string[];
selectRelations: string[];
countRelations: string[];
}

View File

@ -1,6 +1,6 @@
import { STATUS } from "src/core/strings/constants/base.constants"; import { STATUS } from 'src/core/strings/constants/base.constants';
import { BaseEntity } from "./base.entity"; import { BaseEntity } from './base.entity';
export interface BaseStatusEntity extends BaseEntity { export interface BaseStatusEntity extends BaseEntity {
status: STATUS; status: STATUS;
} }

View File

@ -1,10 +1,10 @@
import { BaseCoreEntity } from "./base-core.entity"; import { BaseCoreEntity } from './base-core.entity';
export interface BaseEntity extends BaseCoreEntity { export interface BaseEntity extends BaseCoreEntity {
creator_id: string; creator_id: string;
creator_name: string; creator_name: string;
editor_id: string; editor_id: string;
editor_name: string; editor_name: string;
created_at: number; created_at: number;
updated_at: number; updated_at: number;
} }

View File

@ -1,52 +1,57 @@
import { Inject, Injectable, Logger } from "@nestjs/common"; import { Inject, Injectable, Logger } from '@nestjs/common';
import { UserProvider, UsersSession } from "src/core/sessions"; import { UserProvider, UsersSession } from 'src/core/sessions';
import { BLANK_USER } from "src/core/strings/constants/base.constants"; import { BLANK_USER } from 'src/core/strings/constants/base.constants';
import { TABLE_NAME } from "src/core/strings/constants/table.constants"; import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { RelationParam } from '../entities/base-filter.entity';
@Injectable() @Injectable()
export abstract class BaseReadManager { export abstract class BaseReadManager {
public user: UsersSession;
public user: UsersSession; public dataService: any;
public dataService: any; public queryBuilder: any;
public queryBuilder: any; protected tableName: TABLE_NAME;
protected tableName: TABLE_NAME; abstract get relations(): RelationParam;
@Inject() abstract get selects(): string[];
protected userProvider: UserProvider; @Inject()
protected userProvider: UserProvider;
private readonly baseLog = new Logger(BaseReadManager.name); private readonly baseLog = new Logger(BaseReadManager.name);
setUser() { setUser() {
try { try {
this.user = this.userProvider?.user; this.user = this.userProvider?.user;
} catch (error) { } catch (error) {
this.user = BLANK_USER; this.user = BLANK_USER;
}
} }
}
setService(dataService) { setService(dataService, tableName) {
this.dataService = dataService; this.dataService = dataService;
this.queryBuilder = this.dataService.getRepository().createQueryBuilder(this.tableName); this.tableName = tableName;
} this.queryBuilder = this.dataService
.getRepository()
.createQueryBuilder(this.tableName);
}
async execute(): Promise<void> { async execute(): Promise<void> {
this.baseLog.log(`prepareData`, BaseReadManager.name); this.baseLog.log(`prepareData`, BaseReadManager.name);
await this.prepareData(); await this.prepareData();
this.baseLog.log(`beforeProcess`, BaseReadManager.name); this.baseLog.log(`beforeProcess`, BaseReadManager.name);
await this.beforeProcess(); await this.beforeProcess();
this.baseLog.log('process', BaseReadManager.name);
await this.process();
this.baseLog.log('afterProcess', BaseReadManager.name); this.baseLog.log('process', BaseReadManager.name);
await this.afterProcess(); await this.process();
}
abstract prepareData(): Promise<void>; this.baseLog.log('afterProcess', BaseReadManager.name);
await this.afterProcess();
}
abstract beforeProcess(): Promise<void>; abstract prepareData(): Promise<void>;
abstract process(): Promise<void>; abstract beforeProcess(): Promise<void>;
abstract afterProcess(): Promise<void>; abstract process(): Promise<void>;
}
abstract afterProcess(): Promise<void>;
}

View File

@ -1,85 +1,102 @@
import { BadRequestException, Inject, Injectable, Logger } from "@nestjs/common"; import { Inject, Injectable, Logger } from '@nestjs/common';
import { EventBus } from "@nestjs/cqrs"; import { EventBus } from '@nestjs/cqrs';
import { UserProvider, UsersSession } from "src/core/sessions"; import { UserProvider, UsersSession } from 'src/core/sessions';
import { BLANK_USER } from "src/core/strings/constants/base.constants"; import { BLANK_USER } from 'src/core/strings/constants/base.constants';
import { EventTopics } from "src/core/strings/constants/interface.constants"; import {
import { QueryRunner } from "typeorm"; EventTopics,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { QueryRunner } from 'typeorm';
@Injectable() @Injectable()
export abstract class BaseManager { export abstract class BaseManager {
public user: UsersSession; public user: UsersSession;
public queryRunner: QueryRunner; public dataService: any;
public dataService: any; protected data: any;
protected data: any; public queryRunner: QueryRunner;
@Inject() protected tableName: TABLE_NAME;
protected userProvider: UserProvider; @Inject()
@Inject() protected userProvider: UserProvider;
protected eventBus: EventBus; @Inject()
protected eventBus: EventBus;
abstract get validateRelations(): validateRelations[];
private readonly baseLog = new Logger(BaseManager.name); // sebagai optional yang dapat digunakan
public dataServiceFirstOpt: any;
setUser() { // sebagai optional yang dapat digunakan
try { public dataServiceSecondOpt: any;
this.user = this.userProvider?.user;
} catch (error) { private readonly baseLog = new Logger(BaseManager.name);
this.user = BLANK_USER;
} setUser() {
try {
this.user = this.userProvider?.user ?? BLANK_USER;
} catch (error) {
this.user = BLANK_USER;
} }
}
setService(dataService) { setService(
this.dataService = dataService; dataService,
this.queryRunner = this.dataService.getRepository().manager.connection.createQueryRunner(); tableName,
dataServiceOpt = null,
dataServiceSecondOpt = null,
) {
this.dataService = dataService;
this.tableName = tableName;
this.queryRunner = this.dataService
.getRepository()
.manager.connection.createQueryRunner(tableName);
if (dataServiceOpt) this.dataServiceFirstOpt = dataServiceOpt;
if (dataServiceSecondOpt) this.dataServiceSecondOpt = dataServiceSecondOpt;
}
abstract get eventTopics(): EventTopics[];
async execute(): Promise<void> {
try {
this.setUser();
this.queryRunner.startTransaction();
this.baseLog.verbose('prepareData');
await this.prepareData();
if (!this.dataService) {
throw new Error('data or service not implemented.');
}
this.baseLog.verbose('validateProcess');
await this.validateProcess();
this.baseLog.verbose('beforeProcess');
await this.beforeProcess();
this.baseLog.verbose('process');
await this.process();
this.baseLog.verbose('afterProcess');
await this.afterProcess();
this.baseLog.verbose('commitTransaction');
await this.queryRunner.commitTransaction();
} catch (e) {
if (e.response) throw new Error(JSON.stringify(e.response));
else throw new Error(e.message);
} finally {
await this.queryRunner.release();
} }
}
abstract get eventTopics(): EventTopics[]; abstract prepareData(): Promise<void>;
async execute(): Promise<void> { abstract validateProcess(): Promise<void>;
try {
this.setUser();
this.queryRunner.startTransaction(); abstract beforeProcess(): Promise<void>;
this.baseLog.verbose('prepareData');
await this.prepareData();
if (!this.data || !this.dataService) { abstract process(): Promise<void>;
throw new Error("data or service not implemented.");
}
this.baseLog.verbose('validateProcess'); abstract afterProcess(): Promise<void>;
await this.validateProcess(); }
this.baseLog.verbose('beforeProcess');
await this.beforeProcess();
this.baseLog.verbose('process');
await this.process();
this.baseLog.verbose('afterProcess');
await this.afterProcess();
this.baseLog.verbose('commitTransaction');
await this.queryRunner.commitTransaction();
this.publishEvents();
await this.queryRunner.release();
} catch (e) {
if (e.response) throw new Error(JSON.stringify(e.response));
else throw new Error(e.message);
}
}
abstract prepareData(): Promise<void>;
abstract validateProcess(): Promise<void>;
abstract beforeProcess(): Promise<void>;
abstract process(): Promise<void>;
abstract afterProcess(): Promise<void>;
async publishEvents() {
if (!this.eventTopics.length) return
};
}

View File

@ -0,0 +1,107 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseManager } from '../base.manager';
import { HttpStatus, NotFoundException } from '@nestjs/common';
import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';
export abstract class BaseBatchDeleteManager<Entity> extends BaseManager {
protected dataIds: string[];
protected result: BatchResult;
abstract get entityTarget(): any;
setData(ids: string[]): void {
this.dataIds = ids;
}
validateProcess(): Promise<void> {
return;
}
prepareData(): Promise<void> {
return;
}
async process(): Promise<void> {
let totalFailed = 0;
let totalSuccess = 0;
const messages = [];
for (const id of this.dataIds) {
try {
const entity = await this.dataService.getOneByOptions({
where: {
id: id,
},
});
if (!entity) {
throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND,
message: `Gagal! data dengan id ${id} tidak ditemukan`,
error: 'Entity Not Found',
});
}
await this.validateData(entity);
await new ValidateRelationHelper(
id,
this.dataService,
this.validateRelations,
this.tableName,
).execute();
await this.dataService.deleteById(
this.queryRunner,
this.entityTarget,
id,
);
this.publishEvents(entity, entity);
totalSuccess = totalSuccess + 1;
} catch (error) {
totalFailed = totalFailed + 1;
messages.push(error.response?.message ?? error.message);
}
}
this.result = {
total_items: this.dataIds.length,
total_failed: totalFailed,
total_success: totalSuccess,
messages: messages,
};
}
abstract validateData(data: Entity): Promise<void>;
abstract getResult(): BatchResult;
async publishEvents(dataOld, dataNew) {
this.eventBus.publish(
new RecordLog({
id: dataNew['id'],
old: dataOld,
data: dataNew,
user: this.user,
description: `${this.user.name} delete batch data ${this.tableName}`,
module: this.tableName,
op: OPERATION.DELETE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
this.eventBus.publishAll([
new topic.topic({
id: dataNew['id'],
old: dataOld,
data: dataNew,
user: this.user,
description: '',
module: this.tableName,
op: OPERATION.UPDATE,
}),
]);
}
}
}

View File

@ -0,0 +1,173 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseManager } from '../base.manager';
import { HttpStatus, NotFoundException } from '@nestjs/common';
import { OPERATION, STATUS } from 'src/core/strings/constants/base.constants';
import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import * as _ from 'lodash';
export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
protected dataIds: string[];
protected relations: string[] = [];
protected result: BatchResult;
protected dataStatus: STATUS;
protected oldData: Entity;
abstract get entityTarget(): any;
setData(ids: string[], status: STATUS): void {
/**
* // TODO: Handle case confirm multiple tabs;
* Pola ids yang dikirim dirubah menjadi data_id___updated_at
* Untuk mendapatkan value id nya saja dan menghindari breaking change
* karena sudah digunakan sebelumnya lakukan split dari data ids yang dikirim
* Example:
* this.dataIds = ids.map((i)=> {
* return i.split('___')[0]
* })
*
* Simpan data ids yang mempunyai update_at kedalam valiable baru
* Example:
* this.dataIdsWithDate = ids.map((i)=> {
* return {
* id: i.split('___')[0],
* updated_at: i.split('___')[1]
* }
* })
*/
this.dataIds = ids;
this.dataStatus = status;
}
validateProcess(): Promise<void> {
return;
}
prepareData(): Promise<void> {
return;
}
async process(): Promise<void> {
let totalFailed = 0;
let totalSuccess = 0;
const messages = [];
/**
* // TODO: Handle case confirm multiple tabs;
* Lopping data diambil dari dataIdsWithDate
* exp: for (const item of this.dataIdsWithDate)
*/
for (const id of this.dataIds) {
try {
/**
* // TODO: Handle case confirm multiple tabs;
* buat variable:
* const id = item.id
* const updated_at = item.updated_at
*/
const entity = await this.dataService.getOneByOptions({
where: {
id: id,
},
relations: this.relations,
});
if (!entity) {
throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND,
message: `Gagal! data dengan id ${id} tidak ditemukan`,
error: 'Entity Not Found',
});
}
this.oldData = _.cloneDeep(entity);
await this.validateData(entity);
Object.assign(entity, {
status: this.dataStatus,
editor_id: this.user.id,
editor_name: this.user.name,
updated_at: new Date().getTime(),
});
await new ValidateRelationHelper(
id,
this.dataService,
this.validateRelations,
this.tableName,
).execute();
/**
* // TODO: Handle case confirm multiple tabs;
* lakukan update data dengan where condition id dan updated_at
* EXPECTATION => status akan berubah jika updated_at yang dikirim dari FE sama dengen yang di database
* IF => updated_at beda tidak perlu melakukan update status dan tidak perlu memanggil eventBus tetapi tetap dihitung sebagai aksi yang berhasil
* IF => FE tidak menambahkan updated_at makan lakukan update dan publishEvent
*/
const result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: id },
entity,
);
this.publishEvents(this.oldData, result);
totalSuccess = totalSuccess + 1;
} catch (error) {
totalFailed = totalFailed + 1;
messages.push(error.response?.message ?? error.message);
}
}
this.result = {
total_items: this.dataIds.length,
total_failed: totalFailed,
total_success: totalSuccess,
messages: messages,
};
}
abstract validateData(data: Entity): Promise<void>;
abstract getResult(): BatchResult;
async publishEvents(dataOld, dataNew) {
this.eventBus.publish(
new RecordLog({
id: dataNew['id'],
old: dataOld,
data: dataNew,
user: this.user,
description: `${this.user.name} update batch data ${this.tableName}`,
module: this.tableName,
op: OPERATION.UPDATE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (topic.relations?.length) {
data = await this.dataService.getOneByOptions({
where: {
id: dataNew.id,
},
relations: topic.relations,
});
}
this.eventBus.publishAll([
new topic.topic({
id: data?.['id'] ?? dataNew?.['id'],
old: dataOld,
data: data ?? dataNew,
user: this.user,
description: '',
module: this.tableName,
op: OPERATION.UPDATE,
}),
]);
}
}
}

View File

@ -0,0 +1,152 @@
import { BaseManager } from '../base.manager';
import {
EventTopics,
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { HttpStatus, UnprocessableEntityException } from '@nestjs/common';
import { SelectQueryBuilder } from 'typeorm';
export abstract class BaseChangePosition<Entity> extends BaseManager {
protected result: Entity;
protected duplicateColumn: string[];
protected startData: Entity;
protected endData: Entity;
protected columnSort: string;
protected firstDataId: number;
protected lastSort: number;
protected sortTo: number;
abstract get entityTarget(): any;
setData(entity: Entity, columnSort: string): void {
this.data = entity;
this.columnSort = columnSort;
}
async beforeProcess(): Promise<void> {
if (!this.data?.end || this.data.start == this.data?.end) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: 'Gagal! tolong pindahkan ke posisi lain',
error: 'Unprocessable Entity',
});
}
this.startData = await this.dataService.getOneByOptions({
where: {
id: this.data.start,
},
});
if (!this.startData) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! data dengan id : ${this.data.start} tidak ditemukan`,
error: 'Unprocessable Entity',
});
}
this.endData = await this.dataService.getOneByOptions({
where: {
id: this.data.end,
},
});
if (!this.endData) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! data dengan id : ${this.data.end} tidak ditemukan`,
error: 'Unprocessable Entity',
});
}
if (this.endData[this.columnSort] > this.startData[this.columnSort]) {
// drag from up
this.firstDataId = this.startData[this.columnSort];
this.lastSort = this.endData[this.columnSort];
this.sortTo = this.lastSort;
} else if (
this.endData[this.columnSort] < this.startData[this.columnSort]
) {
// drag from bottom
this.firstDataId = this.endData[this.columnSort];
this.lastSort = this.startData[this.columnSort];
this.sortTo = this.firstDataId;
}
}
async prepareData(): Promise<void> {
Object.assign(this.data, {
creator_id: this.user.id,
creator_name: this.user.name,
created_at: new Date().getTime(),
updated_at: new Date().getTime(),
});
}
async validateProcess(): Promise<void> {
return;
}
async process(): Promise<void> {
let dataArrange: Entity[];
const queryBuilder = this.dataService
.getRepository()
.createQueryBuilder(this.tableName)
.where(`${this.tableName}.${this.columnSort} between :data1 and :data2`, {
data1: this.firstDataId,
data2: this.lastSort,
});
const datas = await queryBuilder
.orderBy(`${this.tableName}.${this.columnSort}`, 'ASC')
.getManyAndCount();
if (datas[0].length) {
let dataFirst = datas[0][0][this.columnSort];
const data = datas[0];
const length = datas[1];
if (this.endData[this.columnSort] > this.startData[this.columnSort]) {
// drag from above
const dataDragged = data[0];
const arraySlice = data.slice(1, length);
dataArrange = arraySlice.concat([dataDragged]);
} else if (
this.endData[this.columnSort] < this.startData[this.columnSort]
) {
// drag from bottom
const dataDragged = data[length - 1];
const arraySlice = data.slice(0, length - 1);
dataArrange = [dataDragged].concat(arraySlice);
}
for (let i = 0; i < length; i++) {
dataArrange[i][this.columnSort] = dataFirst;
dataFirst++;
}
await this.dataService.createMany(
this.queryRunner,
this.entityTarget,
dataArrange,
);
}
}
get validateRelations(): validateRelations[] {
return [];
}
get eventTopics(): EventTopics[] {
return [];
}
getResult(): string {
return `Success! Data ${this.startData['name']} successfully moved to ${this.sortTo}`;
}
}

View File

@ -1,40 +1,111 @@
import { BaseManager } from "../base.manager"; import { CheckDuplicateHelper } from 'src/core/helpers/query/check-duplicate.helpers';
import { Injectable } from "@nestjs/common"; import { BaseManager } from '../base.manager';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';
import {
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { MoveFilePathHelper } from 'src/core/helpers/path/move-file-path.helper';
@Injectable()
export abstract class BaseCreateManager<Entity> extends BaseManager { export abstract class BaseCreateManager<Entity> extends BaseManager {
protected result: Entity;
protected result: Entity; protected duplicateColumn: string[];
protected duplicateColumn: string[]; abstract get entityTarget(): any;
abstract get entityTarget(): any; abstract get uniqueColumns(): columnUniques[];
setData(entity: Entity): void { setData(entity: Entity): void {
this.data = entity; this.data = entity;
}
get validateRelations(): validateRelations[] {
return [];
}
async prepareData(): Promise<void> {
Object.assign(this.data, {
creator_id: this.user.id,
creator_name: this.user.name,
created_at: new Date().getTime(),
updated_at: new Date().getTime(),
});
}
async validateProcess(): Promise<void> {
if (this.uniqueColumns.length) {
await new CheckDuplicateHelper(
this.dataService,
this.tableName,
this.uniqueColumns,
this.data,
).execute();
}
return;
}
async process(): Promise<void> {
const keys = Object.keys(this.data);
if (
(keys.includes('qr_image') || keys.includes('image_url')) &&
(this.data['image_url']?.includes('tmp') ||
this.data['qr_image']?.includes('tmp'))
) {
await MoveFilePathHelper(this.data);
} }
async prepareData(): Promise<void> { this.result = await this.dataService.create(
Object.assign(this.data, { this.queryRunner,
creator_id: this.user.id, this.entityTarget,
creator_name: this.user.name, this.data,
created_at: new Date().getTime(), );
updated_at: new Date().getTime(),
this.publishEvents();
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.result['id'],
},
});
}
async publishEvents() {
this.eventBus?.publish(
new RecordLog({
id: this.result['id'],
old: null,
data: this.result,
user: this.user,
description: '',
module: this.tableName,
op: OPERATION.CREATE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (!topic.data) {
data = await this.dataService.getOneByOptions({
where: {
id: this.result['id'],
},
relations: topic.relations,
}); });
} }
async process(): Promise<void> { this.eventBus.publishAll([
this.result = await this.dataService.create( new topic.topic({
this.queryRunner, id: this.result['id'],
this.entityTarget, old: null,
this.data, data: data ?? topic.data,
); user: this.user,
description: '',
module: this.tableName,
op: OPERATION.CREATE,
}),
]);
} }
}
async getResult(): Promise<Entity> { }
return await this.dataService.getOneByOptions({
where: {
id: this.result['id']
}
})
}
}

View File

@ -0,0 +1,54 @@
import { validateRelations } from 'src/core/strings/constants/interface.constants';
import { BaseManager } from '../base.manager';
import { OPERATION } from 'src/core/strings/constants/base.constants';
export abstract class BaseCustomManager<Entity> extends BaseManager {
protected result: any;
abstract get entityTarget(): any;
setData(entity: any): void {
this.data = entity;
}
get validateRelations(): validateRelations[] {
return [];
}
async prepareData(): Promise<void> {
if (this.data)
Object.assign(this.data, {
editor_id: this.user.id,
editor_name: this.user.name,
updated_at: new Date().getTime(),
});
}
abstract getResult(): any;
async publishEvents() {
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (!topic.data) {
data = await this.dataService.getOneByOptions({
where: {
id: this.result['id'],
},
relations: topic.relations,
});
}
this.eventBus.publishAll([
new topic.topic({
id: data?.['id'] ?? topic?.data?.['id'],
old: null,
data: data ?? topic.data,
user: this.user,
description: '',
module: this.tableName,
op: OPERATION.UPDATE,
}),
]);
}
}
}

View File

@ -1,41 +1,80 @@
import { HttpStatus, Injectable, UnauthorizedException, UnprocessableEntityException } from "@nestjs/common"; import { HttpStatus, UnprocessableEntityException } from '@nestjs/common';
import { BaseManager } from "../base.manager"; import { BaseManager } from '../base.manager';
import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';
@Injectable()
export abstract class BaseDeleteManager<Entity> extends BaseManager { export abstract class BaseDeleteManager<Entity> extends BaseManager {
protected dataId: string;
protected dataId: string; protected result: Entity;
protected result: Entity; abstract get entityTarget(): any;
abstract get entityTarget(): any;
setData(id: string): void { setData(id: string): void {
this.dataId = id; this.dataId = id;
}
async prepareData(): Promise<void> {
this.data = await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
});
if (!this.data)
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! Data denga id ${this.dataId} tidak ditemukan`,
error: 'Unprocessable Entity',
});
return;
}
async process(): Promise<void> {
await new ValidateRelationHelper(
this.dataId,
this.dataService,
this.validateRelations,
this.tableName,
).execute();
await this.dataService.deleteById(
this.queryRunner,
this.entityTarget,
this.dataId,
);
this.publishEvents();
}
abstract getResult(): string;
async publishEvents() {
this.eventBus.publish(
new RecordLog({
id: this.data['id'],
old: null,
data: this.data,
user: this.user,
description: `${this.user.name} delete data ${this.tableName}`,
module: this.tableName,
op: OPERATION.CREATE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
this.eventBus.publishAll([
new topic.topic({
id: topic.data['id'],
old: this.data,
data: topic.data,
user: this.user,
description: '',
module: this.tableName,
op: OPERATION.DELETE,
}),
]);
} }
}
async prepareData(): Promise<void> { }
this.data = await this.dataService.getOneByOptions({
where: {
id: this.dataId
}
})
if (!this.data)
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Data with id ${this.dataId} not found`,
error: 'Unprocessable Entity',
});
return;
}
async process(): Promise<void> {
await this.dataService.deleteById(
this.queryRunner,
this.entityTarget,
this.dataId,
);
}
abstract getResult(): string;
}

View File

@ -1,24 +1,40 @@
import { BaseReadManager } from "../base-read.manager"; import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
import { BaseReadManager } from '../base-read.manager';
export abstract class BaseDetailManager<Entity> extends BaseReadManager { export abstract class BaseDetailManager<Entity> extends BaseReadManager {
protected dataId: string;
protected result: Entity;
abstract get setFindProperties(): any;
protected dataId: string; setData(dataId: string): void {
protected result: Entity; this.dataId = dataId;
}
abstract get selectData(): string[]; async process(): Promise<void> {
abstract get relationData(): string[]; const { joinRelations, selectRelations, countRelations } = this.relations;
abstract get setFindProperties(): any; if (joinRelations?.length)
joinRelationHelper(joinRelations, this.tableName, this.queryBuilder);
if (selectRelations?.length)
joinRelationHelper(
selectRelations,
this.tableName,
this.queryBuilder,
'select',
);
if (countRelations?.length)
joinRelationHelper(
countRelations,
this.tableName,
this.queryBuilder,
'count',
);
setData(dataId: string): void { if (this.selects?.length) this.queryBuilder.select(this.selects);
this.dataId = dataId; this.queryBuilder.where(this.setFindProperties);
} this.result = await this.queryBuilder.getOne();
}
async process(): Promise<void> { getResult(): Entity {
this.queryBuilder.select(this.selectData).where(this.setFindProperties); return this.result;
this.result = await this.queryBuilder.getOne(); }
} }
getResult(): Entity {
return this.result;
}
}

View File

@ -1,54 +1,88 @@
import { PaginationResponse } from "src/core/response/domain/ok-response.interface"; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { BaseReadManager } from "../base-read.manager"; import { BaseReadManager } from '../base-read.manager';
import { SelectQueryBuilder } from "typeorm"; import { SelectQueryBuilder } from 'typeorm';
import { BaseFilterEntity } from "../../entities/base-filter.entity"; import { SpecificSearchFilter } from 'src/core/helpers/query/specific-search.helper';
import { Param, SpecificSearchFilter } from "src/core/helpers/query/specific-search.helper"; import {
getOrderBy,
setQueryFilterDefault,
} from 'src/core/helpers/query/default-filter.helper';
import { Param } from '../../entities/base-filter.entity';
import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
import { STATUS } from 'src/core/strings/constants/base.constants';
export abstract class BaseIndexManager<Entity> extends BaseReadManager { export abstract class BaseIndexManager<Entity> extends BaseReadManager {
protected result: PaginationResponse<Entity>;
protected result: PaginationResponse<Entity>; public filterParam: any;
public filterParam: BaseFilterEntity; abstract get specificFilter(): Param[];
abstract get specificFilter(): Param[];
setFilterParam(param: BaseFilterEntity): void { setFilterParam(param: any): void {
this.filterParam = param; this.filterParam = param;
}
async process(): Promise<void> {
const specificFilter = this.specificFilter;
const { joinRelations, selectRelations, countRelations } = this.relations;
if (joinRelations?.length)
joinRelationHelper(joinRelations, this.tableName, this.queryBuilder);
if (selectRelations?.length)
joinRelationHelper(
selectRelations,
this.tableName,
this.queryBuilder,
'select',
);
if (countRelations?.length)
joinRelationHelper(
countRelations,
this.tableName,
this.queryBuilder,
'count',
);
if (this.selects?.length) this.queryBuilder.select(this.selects);
if (this.filterParam.statuses?.length > 0) {
const data = this.filterParam.statuses.map((status) => {
const statusData = status.includes("'")
? status.trim().replace(/'/g, "''").replace(/\s+/g, ' ')
: status.trim().replace(/\s+/g, ' ');
// jika searching status terdapat dalam enum, maka dia mencari specific data
// ? karena jika tidak, ketika dia search "active" maka "inactive" juga ikut
return `'${STATUS[statusData.toUpperCase()]}'`;
});
const exist = specificFilter.find((item) => item.isStatus);
if (!exist) {
specificFilter.push({
cols: `${this.tableName}.status::text`,
data: data,
});
}
} }
async process(): Promise<void> { new SpecificSearchFilter<Entity>(
// const filterSearch: string[] = this.setFilterSearch(); this.queryBuilder,
this.tableName,
specificFilter,
).getFilter();
// this.queryBuilder.andWhere( getOrderBy(this.filterParam, this.queryBuilder, this.tableName);
// new Brackets((qb) => { this.setQueryFilter(this.queryBuilder);
// filterSearch.map((fSearch) => { setQueryFilterDefault(this.queryBuilder, this.filterParam, this.tableName);
// qb.orWhere(`${fSearch} ILIKE :query`, {
// query: `%${
// this.filterParam.q.trim().replace(/\s+/g, ' ') ?? ''
// }%`,
// });
// });
// }),
// );
new SpecificSearchFilter<Entity>(this.queryBuilder, this.tableName, this.specificFilter).getFilter(); this.result = await this.dataService.getIndex(
this.setQueryFilter(this.queryBuilder); this.queryBuilder,
this.filterParam,
);
}
this.result = await this.dataService.getIndex( abstract setQueryFilter(
this.queryBuilder, queryBuilder: SelectQueryBuilder<Entity>,
this.filterParam, ): SelectQueryBuilder<Entity>;
);
}
setFilterSearch(): string[] { getResult(): PaginationResponse<Entity> {
return []; return this.result;
} }
}
abstract setQueryFilter(
queryBuilder: SelectQueryBuilder<Entity>,
): SelectQueryBuilder<Entity>;
getResult(): PaginationResponse<Entity> {
return this.result;
}
}

View File

@ -1,42 +1,126 @@
import { Injectable } from "@nestjs/common"; import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { BaseManager } from "../base.manager"; import { BaseManager } from '../base.manager';
import { STATUS } from "src/core/strings/constants/base.constants"; import {
import { UserPrivilegeModel } from "src/modules/user-related/user-privilege/data/model/user-privilege.model"; OPERATION,
QUEUE_STATUS,
STATUS,
} from 'src/core/strings/constants/base.constants';
import * as _ from 'lodash';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
@Injectable()
export abstract class BaseUpdateStatusManager<Entity> extends BaseManager { export abstract class BaseUpdateStatusManager<Entity> extends BaseManager {
protected dataId: string;
protected result: Entity;
protected oldData: Entity;
protected dataStatus: STATUS | QUEUE_STATUS;
protected relations = [];
protected duplicateColumn: string[];
abstract get entityTarget(): any;
protected dataId: string; setData(id: string, status: STATUS | QUEUE_STATUS): void {
protected result: Entity; /**
protected dataStatus: STATUS; * // TODO: Handle case confirm multiple tabs;
protected duplicateColumn: string[]; * Pola id yang dikirim dirubah menjadi data_id___updated_at
abstract get entityTarget(): any; * Untuk mendapatkan value id nya saja dan menghindari breaking change
* karena sudah digunakan sebelumnya lakukan split dari data ids yang dikirim
* Example:
* this.dataId = id.split('___')[0]
*
* Simpan data id yang mempunyai update_at kedalam valiable baru
* Example:
* this.dataIdsWithDate = {
* id: id.split('___')[0],
* updated_at: id.split('___')[1]
* }
*/
setData(id: string, status: STATUS): void { this.dataId = id;
this.dataId = id; this.dataStatus = status;
this.dataStatus = status; }
}
async prepareData(): Promise<void> { async prepareData(): Promise<void> {
this.data = new UserPrivilegeModel(); this.data = await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
relations: this.relations,
});
this.oldData = _.cloneDeep(this.data);
Object.assign(this.data, { Object.assign(this.data, {
editor_id: this.user.id, editor_id: this.user.id,
editor_name: this.user.name, editor_name: this.user.name,
updated_at: new Date().getTime(), updated_at: new Date().getTime(),
status: this.dataStatus,
});
}
async process(): Promise<void> {
await new ValidateRelationHelper(
this.dataId,
this.dataService,
this.validateRelations,
this.tableName,
).execute();
/**
* // TODO: Handle case confirm multiple tabs;
* IF => updated_at sama dengen data yang di database
* THEN =>
* - Lakukan update data dengan where condition id dan updated_at
* - EXPECTATION = > status akan berubah jika updated_at yang dikirim dari FE sama dengen yang di database
* IF => updated_at beda maka retun curent data tanpa harus malakukan update status dan publish event
* IF => FE tidak menambahkan updated_at makan lakukan update dan publishEvent
*/
this.result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.dataId },
this.data,
);
this.publishEvents();
}
abstract getResult(): string;
async publishEvents() {
this.eventBus.publish(
new RecordLog({
id: this.result['id'],
old: this.oldData,
data: this.result,
user: this.user,
description: `${this.user.name} update status data ${this.tableName} to ${this.dataStatus}`,
module: this.tableName,
op: OPERATION.UPDATE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (!topic.data) {
data = await this.dataService.getOneByOptions({
where: {
id: this.dataId, id: this.dataId,
status: this.dataStatus, },
relations: topic.relations,
}); });
} }
async process(): Promise<void> { this.eventBus.publishAll([
this.result = await this.dataService.update( new topic.topic({
this.queryRunner, id: data?.['id'] ?? topic?.data?.['id'],
this.entityTarget, old: this.oldData,
{ id: this.dataId }, data: data ?? topic.data,
this.data, user: this.user,
); description: '',
module: this.tableName,
op: OPERATION.UPDATE,
}),
]);
} }
}
abstract getResult(): string; }
}

View File

@ -1,41 +1,116 @@
import { Injectable } from "@nestjs/common"; import { CheckDuplicateHelper } from 'src/core/helpers/query/check-duplicate.helpers';
import { BaseManager } from "../base.manager"; import { BaseManager } from '../base.manager';
import { ValidateRelationHelper } from 'src/core/helpers/validation/validate-relation.helper';
import { columnUniques } from 'src/core/strings/constants/interface.constants';
import { RecordLog } from 'src/modules/configuration/log/domain/entities/log.event';
import { OPERATION } from 'src/core/strings/constants/base.constants';
import { HttpStatus, NotFoundException } from '@nestjs/common';
@Injectable()
export abstract class BaseUpdateManager<Entity> extends BaseManager { export abstract class BaseUpdateManager<Entity> extends BaseManager {
protected dataId: string;
protected result: Entity;
protected oldData: Entity;
protected duplicateColumn: string[];
abstract get entityTarget(): any;
abstract get uniqueColumns(): columnUniques[];
protected dataId: string; setData(id: string, entity: Entity): void {
protected result: Entity; this.dataId = id;
protected duplicateColumn: string[]; this.data = entity;
abstract get entityTarget(): any; }
setData(id: string, entity: Entity): void { async prepareData(): Promise<void> {
this.dataId = id; this.oldData = await this.dataService.getOneByOptions({
this.data = entity; where: { id: this.dataId },
});
if (!this.oldData) {
throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND,
message: `Gagal! Data denga id ${this.dataId} tidak ditemukan`,
error: 'Entity Not Found',
});
} }
async prepareData(): Promise<void> { Object.assign(this.data, {
Object.assign(this.data, { editor_id: this.user.id,
editor_id: this.user.id, editor_name: this.user.name,
editor_name: this.user.name, updated_at: new Date().getTime(),
updated_at: new Date().getTime(), });
if (this.uniqueColumns.length) {
await new CheckDuplicateHelper(
this.dataService,
this.tableName,
this.uniqueColumns,
this.data,
this.dataId,
).execute();
}
}
async process(): Promise<void> {
await new ValidateRelationHelper(
this.dataId,
this.dataService,
this.validateRelations,
this.tableName,
).execute();
this.result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.dataId },
this.data,
);
this.publishEvents();
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
});
}
async publishEvents() {
this.eventBus.publish(
new RecordLog({
id: this.result['id'],
old: this.oldData,
data: this.result,
user: this.user,
description: `${this.user.name} update data ${this.tableName}`,
module: this.tableName,
op: OPERATION.UPDATE,
}),
);
if (!this.eventTopics.length) return;
for (const topic of this.eventTopics) {
let data;
if (!topic.data) {
data = await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
relations: topic.relations,
}); });
} }
async process(): Promise<void> { this.eventBus.publishAll([
this.result = await this.dataService.update( new topic.topic({
this.queryRunner, id: topic.data?.['id'] ?? this.dataId,
this.entityTarget, old: this.oldData,
{ id: this.dataId }, data: data ?? topic.data,
this.data, user: this.user,
); description: '',
module: this.tableName,
op: OPERATION.UPDATE,
}),
]);
} }
}
async getResult(): Promise<Entity> { }
return await this.dataService.getOneByOptions({
where: {
id: this.dataId
}
})
}
}

View File

@ -1,7 +1,13 @@
import { BaseDataOrchestrator } from "./base-data.orchestrator"; import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseDataOrchestrator } from './base-data.orchestrator';
export abstract class BaseDataTransactionOrchestrator<Entity> extends BaseDataOrchestrator<Entity> { export abstract class BaseDataTransactionOrchestrator<
abstract active(dataId: string): Promise<String>; Entity,
abstract confirm(dataId: string): Promise<String>; > extends BaseDataOrchestrator<Entity> {
abstract inactive(dataId: string): Promise<String>; abstract active(dataId: string): Promise<string>;
} abstract confirm(dataId: string): Promise<string>;
abstract inactive(dataId: string): Promise<string>;
abstract batchConfirm(dataIds: string[]): Promise<BatchResult>;
abstract batchActive(dataIds: string[]): Promise<BatchResult>;
abstract batchInactive(dataIds: string[]): Promise<BatchResult>;
}

View File

@ -1,7 +1,8 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
export abstract class BaseDataOrchestrator<Entity> { export abstract class BaseDataOrchestrator<Entity> {
abstract create(data: Entity): Promise<Entity>;
abstract create(data: Entity): Promise<Entity>; abstract update(dataId: string, data: Entity): Promise<Entity>;
abstract update(dataId: string, data: Entity): Promise<Entity>; abstract delete(dataId: string): Promise<string>;
abstract delete(dataId: string): Promise<String>; abstract batchDelete(dataIds: string[]): Promise<BatchResult>;
}
}

View File

@ -1,6 +1,6 @@
import { PaginationResponse } from "src/core/response/domain/ok-response.interface"; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
export abstract class BaseReadOrchestrator<Entity> { export abstract class BaseReadOrchestrator<Entity> {
abstract index(params): Promise<PaginationResponse<Entity>>; abstract index(params): Promise<PaginationResponse<Entity>>;
abstract detail(dataId: string): Promise<Entity>; abstract detail(dataId: string): Promise<Entity>;
} }

View File

@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class BatchIdsDto {
@ApiProperty({ type: [String] })
ids: string[];
}

View File

@ -0,0 +1,4 @@
export class ChangePositionDto {
start: string;
end: string;
}

View File

@ -1,5 +1,5 @@
import { BaseCoreEntity } from "../../domain/entities/base-core.entity"; import { BaseCoreEntity } from '../../domain/entities/base-core.entity';
export class BaseCoreDto implements BaseCoreEntity { export class BaseCoreDto implements BaseCoreEntity {
id: string; id: string;
} }

View File

@ -1,8 +1,14 @@
import { ApiProperty } from "@nestjs/swagger"; import { ApiProperty } from '@nestjs/swagger';
import { BaseFilterEntity } from "../../domain/entities/base-filter.entity"; import { BaseFilterEntity } from '../../domain/entities/base-filter.entity';
import { Transform } from "class-transformer"; import { Transform } from 'class-transformer';
import { IsArray, IsEnum, IsNumber, IsString, ValidateIf } from "class-validator"; import {
import { ORDER_TYPE, STATUS } from "src/core/strings/constants/base.constants"; IsArray,
IsEnum,
IsNumber,
IsString,
ValidateIf,
} from 'class-validator';
import { ORDER_TYPE, STATUS } from 'src/core/strings/constants/base.constants';
export class BaseFilterDto implements BaseFilterEntity { export class BaseFilterDto implements BaseFilterEntity {
@ApiProperty({ type: Number, required: false, default: 1 }) @ApiProperty({ type: Number, required: false, default: 1 })
@ -16,7 +22,7 @@ export class BaseFilterDto implements BaseFilterEntity {
@ValidateIf((body) => body.limit) @ValidateIf((body) => body.limit)
@IsNumber() @IsNumber()
limit = 10; limit = 10;
@ApiProperty({ type: String, required: false }) @ApiProperty({ type: String, required: false })
q: string; q: string;
@ -55,12 +61,6 @@ export class BaseFilterDto implements BaseFilterEntity {
}) })
@IsArray() @IsArray()
@IsString({ each: true }) @IsString({ each: true })
@IsEnum(STATUS, {
message: `Status must be a valid enum ${JSON.stringify(
Object.values(STATUS),
)}`,
each: true,
})
statuses: STATUS[]; statuses: STATUS[];
@ApiProperty({ type: [String], required: false }) @ApiProperty({ type: [String], required: false })

View File

@ -1,7 +1,7 @@
import { STATUS } from "src/core/strings/constants/base.constants"; import { STATUS } from 'src/core/strings/constants/base.constants';
import { BaseStatusEntity } from "../../domain/entities/base-status.entity"; import { BaseStatusEntity } from '../../domain/entities/base-status.entity';
import { BaseDto } from "./base.dto"; import { BaseDto } from './base.dto';
export class BaseStatusDto extends BaseDto implements BaseStatusEntity { export class BaseStatusDto extends BaseDto implements BaseStatusEntity {
status: STATUS; status: STATUS;
} }

View File

@ -1,11 +1,11 @@
import { BaseEntity } from "../../domain/entities/base.entity"; import { BaseEntity } from '../../domain/entities/base.entity';
import { BaseCoreDto } from "./base-core.dto"; import { BaseCoreDto } from './base-core.dto';
export class BaseDto extends BaseCoreDto implements BaseEntity { export class BaseDto extends BaseCoreDto implements BaseEntity {
creator_id: string; creator_id: string;
creator_name: string; creator_name: string;
editor_id: string; editor_id: string;
editor_name: string; editor_name: string;
created_at: number; created_at: number;
updated_at: number; updated_at: number;
} }

View File

@ -1 +1,2 @@
export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE'; export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE';
export const GATE_RESPONSE = 'GATE_RESPONSE';

Some files were not shown because too many files have changed in this diff Show More