From c81c73e763ef686c463b56efc884666885b67c07 Mon Sep 17 00:00:00 2001 From: zdni Date: Mon, 5 Aug 2024 20:07:48 +0800 Subject: [PATCH] export file excel and add DocumentController --- controllers/DocumentController.js | 99 +++++++++++++++++++++++ controllers/PDFController.js | 41 ++++++++++ controllers/TransactionLineController.js | 2 - controllers/VendorController.js | 4 +- controllers/XlsxController.js | 28 ++++++- exports/01 Jul 2024-28 Jul 2024.xlsx | Bin 6986 -> 0 bytes models/Document.js | 2 +- routes/index.js | 7 ++ 8 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 controllers/DocumentController.js create mode 100644 controllers/PDFController.js delete mode 100644 exports/01 Jul 2024-28 Jul 2024.xlsx diff --git a/controllers/DocumentController.js b/controllers/DocumentController.js new file mode 100644 index 0000000..e26797d --- /dev/null +++ b/controllers/DocumentController.js @@ -0,0 +1,99 @@ +import fs from 'fs'; +import Document from "../models/Document.js"; + +import checkValidationObjectId from '../libraries/checkValidationObjectId.js'; + +class DocumentController { + async index(req, res) { + try { + const documents = await Document.find(); + if(!documents) { throw { code: 404, message: "DOCUMENT_DATA_NOT_FOUND", data: null, status: false } } + + return res.status(200).json({ + status: true, + message: "LIST_DOCUMENT", + data: documents + }); + } catch (error) { + return res.status(error.code || 500).json({ + status: false, + message: error.message, + data: null + }); + } + } + + async store(req, res) { + try { + const { name, document_type } = req.body; + if(!name) { return { status: false, code: 428, message: "NAME_IS_REQUIRED" } } + if(!document_type) { return { status: false, code: 428, message: "TYPE_IS_REQUIRED" } } + + const data = new Document({ name: name, document_type: document_type }); + const document = await data.save(); + if(!document) { throw { code: 500, message: "Export File Gagal!", data: null, status: false } } + + return res.status(200).json({ + status: true, + message: "Export File Berhasil!", + data: document, + }) + } catch (error) { + return res.status(error.code || 500).json({ + status: false, + message: error.message, + data: null + }); + } + } + + async destroy(req, res) { + try { + const {id} = req.params + if(!id) { throw { code: 420, message: "ID_REQUIRED", data: null, status: false } } + + const checkObjId = await checkValidationObjectId(id, Document, "DOCUMENT", true) + if(!checkObjId.status) return res.status(checkObjId.code).json({ + status: false, + message: checkObjId.message, + data: null + }); + + const document = await Document.findOneAndDelete({ _id: id }) + if(!document) { throw { code: 500, message: "Gagal menghapus file!", data: null, status: false } } + + const filepath = `exports/${checkObjId.data.name}`; + + fs.stat('foo.txt', function(err, stat) { + if (err == null) { + fs.unlink(filepath, (err) => { + if(err) { + console.log(err) + return res.status(500).json({ + status: false, + message: "Gagal menghapus file pada server!", + data: null + }); + } + }) + } else { + console.log('Some other error: ', err.code); + } + }); + + return res.status(200).json({ + status: true, + message: "Berhasil menghapus file!", + data: document, + }) + } catch (error) { + return res.status(error.code || 500).json({ + status: false, + message: error.message, + data: null + }); + } + } +} + +export default new DocumentController; \ No newline at end of file diff --git a/controllers/PDFController.js b/controllers/PDFController.js new file mode 100644 index 0000000..0d5e451 --- /dev/null +++ b/controllers/PDFController.js @@ -0,0 +1,41 @@ +import Document from "../models/Document.js"; +import TransactionLine from "../models/TransactionLine.js"; + +import TransactionLineService from '../services/TransactionLineService.js'; + +import { fDate } from '../libraries/formatTime.js'; + +class PDFController { + async export(req, res) { + try { + const { startDate, endDate } = req.query; + + const query = await TransactionLineService.generateQuerySearch(req); + if(!query.status) throw { code: query.code, message: "ERROR_QUERY_SEARCH", data: null, status: false } + + let result = TransactionLine.aggregate(query.aggregate); + + const lines = await result; + + const filename = `${fDate(startDate*1)}-${fDate(endDate*1)}.pdf` + // writeFileSync(`exports/${filename}`, pdf); + + const data = new Document({ name: filename, document_type: 'pdf' }); + const document = await data.save(); + + if(!document) { throw { code: 500, message: "Export File Gagal!", data: null, status: false } } + return res.status(200).json({ + status: true, + message: "SUCCESS_EXPORT", + }); + } catch (error) { + if(!error.code) { error.code = 500 } + return res.status(error.code).json({ + status: false, + message: error.message, + }); + } + } +} + +export default new PDFController; \ No newline at end of file diff --git a/controllers/TransactionLineController.js b/controllers/TransactionLineController.js index 654b9dc..42e2b3d 100644 --- a/controllers/TransactionLineController.js +++ b/controllers/TransactionLineController.js @@ -13,8 +13,6 @@ class TransactionController { if(!query.status) throw { code: query.code, message: "Query Pencarian Eror!", data: null, status: false } let result = TransactionLine.aggregate(query.aggregate); - console.log(query.aggregate); - const lines = await result; const total = await TransactionLine.countDocuments(query.aggregate.at(-1)['$match']); diff --git a/controllers/VendorController.js b/controllers/VendorController.js index e278200..fc7042f 100644 --- a/controllers/VendorController.js +++ b/controllers/VendorController.js @@ -113,8 +113,8 @@ class VendorController { data: null }); - // check if account has transaction - const vendors = await TransactionLine.find({ accountId: id }); + // check if vendor has transaction + const vendors = await TransactionLine.find({ vendorId: id }); if(vendors.length > 0) { return res.status(500).json({ status: false, diff --git a/controllers/XlsxController.js b/controllers/XlsxController.js index d4f3677..81788dc 100644 --- a/controllers/XlsxController.js +++ b/controllers/XlsxController.js @@ -1,6 +1,7 @@ import { writeFileSync } from "node:fs"; import { Workbook } from "xlsx-kaku"; +import Document from "../models/Document.js"; import TransactionLine from "../models/TransactionLine.js"; import TransactionLineService from '../services/TransactionLineService.js'; @@ -10,7 +11,6 @@ import { fDate } from '../libraries/formatTime.js'; class XlsxController { async export(req, res) { try { - console.log(req.query) const query = await TransactionLineService.generateQuerySearch(req); if(!query.status) throw { code: query.code, message: "ERROR_QUERY_SEARCH", data: null, status: false } let result = TransactionLine.aggregate(query.aggregate); @@ -19,17 +19,20 @@ class XlsxController { const wb = new Workbook(); const ws = wb.addWorksheet("TRANSAKSI"); + const { startDate, endDate } = req.query; ws.setCell(0, 0, { type: "string", value: "DAFTAR TRANSAKSI", style: { alignment: {horizontal: "center", vertical: "center"} } }); ws.setMergeCell({ ref: "A1:F2" }); ws.setCell(2, 0, { type: "string", value: `${fDate(startDate*1)} sampai ${fDate(endDate*1)}`, style: { alignment: {horizontal: "center", vertical: "center"} } }); ws.setMergeCell({ ref: "A3:F3" }); + ws.setMergeCell({ ref: "A4:F6" }); let row = 3 let currentDate = ''; let number = 0; let income = 0; let expense = 0; + let margin = 0; lines.map((line) => { if(currentDate !== fDate(line.date)) { if(row !== 3) { @@ -38,11 +41,19 @@ class XlsxController { ws.setMergeCell({ ref: `A${row+1}:D${row+1}` }) ws.setCell(row, 4, { type: "number", value: income, style: { alignment: {horizontal: "right", vertical: "center"} } }); ws.setCell(row, 5, { type: "number", value: expense, style: { alignment: {horizontal: "right", vertical: "center"} } }); + + margin = income-expense; + row += 1; + ws.setCell(row, 0, { type: "string", value: "Margin" }); + ws.setMergeCell({ ref: `A${row+1}:D${row+1}` }); + ws.setCell(row, 4, { type: "number", value: margin, style: { alignment: {horizontal: "right", vertical: "center"} } }); + ws.setMergeCell({ ref: `E${row+1}:F${row+1}` }); } number = 0; income = 0; expense = 0; row += 3; + ws.setMergeCell({ ref: `A${row-1}:F${row}` }) currentDate = fDate(line.date); ws.setCell(row, 0, { type: "string", value: `${fDate(line.date*1)}`, style: { alignment: {horizontal: "center", vertical: "center"} } }); @@ -75,9 +86,22 @@ class XlsxController { ws.setMergeCell({ ref: `A${row+1}:D${row+1}` }) ws.setCell(row, 4, { type: "number", value: income, style: { alignment: {horizontal: "right", vertical: "center"} } }); ws.setCell(row, 5, { type: "number", value: expense, style: { alignment: {horizontal: "right", vertical: "center"} } }); + + margin = income-expense; + row += 1; + ws.setCell(row, 0, { type: "string", value: "Margin" }); + ws.setMergeCell({ ref: `A${row+1}:D${row+1}` }); + ws.setCell(row, 4, { type: "number", value: margin, style: { alignment: {horizontal: "right", vertical: "center"} } }); + ws.setMergeCell({ ref: `E${row+1}:F${row+1}` }); const xlsx = wb.generateXlsxSync(); - writeFileSync(`${fDate(startDate*1)}-${fDate(endDate*1)}.xlsx`, xlsx); + const filename = `${fDate(startDate*1)}-${fDate(endDate*1)}.xlsx` + writeFileSync(`exports/${filename}`, xlsx); + + const data = new Document({ name: filename, document_type: 'excel' }); + const document = await data.save(); + + if(!document) { throw { code: 500, message: "Export File Gagal!", data: null, status: false } } return res.status(200).json({ status: true, diff --git a/exports/01 Jul 2024-28 Jul 2024.xlsx b/exports/01 Jul 2024-28 Jul 2024.xlsx deleted file mode 100644 index 692bae54d5a7bd23180097578a50481aac00e714..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6986 zcmZ`;1yEeuvPD7&KDavsg1Zyk26uuxgF6iFI#}?K03ktwyGs}d?(Xgc3qgVeKDqb5 zmmB{5=Tx0twX0TFoz>mDyVq8chkt?t0|WC6CLVmNGk20dt^f-I6ZZrL2K!-GPr}i` z&BDRWNW;s?!qtEUY;RYpv7iLU4)~d(Xf)(7hG>S0f?-IOB6%CwlxaciEpH|I!^diX zwwnU9nx`n}$|7tpKvMpWIW=MQi4o+h4F&Rv;%N7X&9|3+EXR^Txh+~e;7?sdDlsyh zdjfEHG3PpvIQnJzC`Cji6I?2ASq&w>REq*9p(dv`X98~swA3z`?nFavgi^Xw1~k>7 z_N`|9FgE@Pp47Jr>w{XG9MhV7)i3UiXV($HM$JzIZ+t2^G0PjodP9)?wmgHFk5WS9 zq$Su@qYRTbSQ@KNIdiXMo_*iv>w`_pu~&o_;6mw1KsJNRtAwYpDi+dKBK-W_Pc|Ex zghS;LgLHRnoTeVnLX9m(1%Hzp$G~wuClh{$%(W|G<2W%q_I_~UJj`t6d-jRgZIcOS zmLuiFJAkCFUc0gk<=G2~Otdu*no9C@sC%5A%y<4kT5k8gG1-i`i z*dbG!qh#8&NDY>4M4jqVMPOOeDCTax(T&-BYC~AB=^nc$2%oCpdWJVXW)xJYTzU30 zlUZ>>unqf?!+DgGIl*dcb*|i$;au*915)^+wgj)GA>uUiwW&Tn*Q(dY!0|?h8g=bD$Xin;Q!t)IjLYXlaCuUelA2i4($LO2uGmW~ zjhi_Na-JL>_5LLBbq&(j|B_`d03{N|F72$eI*!=6h~v()shO7v&0=X7H9>q`$SBH zu!us*6~AoM%Gb_$tZPMg4HPXwYTI&2hciOQkl zP8zeFF!lY2f~-g1-tqfo)_&}sCwZ6H z-d~xBU{ms*Bx#mCm)@=|K-5&53@bVhF=*PeJt1Mpc9wU#ShQD4nhQb9`!GRkrnQ+K z(2NCJP%{wr^t|C1=WhDbrb#iz&GEB>63=Q|L=8z6oJ=d3P3i#etj`rL$#D+rXDnn( zBNNS3tuIcw`l@fgj!uPj%heqD{7BnZ%@vfrHn#Q?*?D2>I7LA^fQsPYO;?^e%-VE| z@TYswl3bZt9^BLLkhs6jQm`GXE6Bvf!d%_W#oEEj^_Pd-6AhF**l@z{f$HUX3*rgs z_U4iFHmE^+KVOr|INR^c6Wv~t1+(Xe47@zP@>QPbGvq!%5oC-V1`9>}pUa(i0&esJYg$8#c#am<_k2W|KL_QAF|ACV1_izG7#E;4*4=eQyHmv#PC~YLL`? zBM8LfK6XQgfn-~iN>fT}2L8Wku zWb5})(Q+On+!|3tzNHjJ34cVvzWgkku_E2@)7AoAZb8W~wI3|8Az83}Q?C#M=oq|T z>>O80N?OM}GYj6mD`(w3-V*tfU(!*%v(jJOBErC+{V%_6UUn9L5!;$_ zZ?nJ#=rNMo4bZN`wvvnF%*YQHM-1_(2*B0z_;S|S>*6GEK@`#o%`(B5+?nn3z>0`- z$gQ|Fk=tpGKRQccge06mgbC69jlGw7if`$z%8^&WN`mTzqn~ z^`XiKN>&&1>IsZy7ueRGpDq_zuQ0w3OjCfq)hCu?W>OR@8fVMUWRXS2y1omQ?Z-WO z=KAIiMN;j19!smnK%#EjTJVD3K!Faej(mGg}R;TLA{8ThDO!!UN~|a`y!zn{xUjldjmkmdw17Zheh=1Kn&10 z==y4-?FlT-VjB9y_0O(mHaGInF^c!3#w)Qrgo`642AS540H%6?F}TwG;}oqB@4PNw z&vIFkGcjtZy{rTG+F6W5nfz}2$d=cWZ-7dN)H(+1Fjfq?M z0Wfpt#~GQniMmUHA;I!D3klp8ZNbVY(i+5M8|C%Ip4I2}Sl;RZ+~?iYcwW_@+KUh0 zhHP4uEd6&^e2KX#d21@_jssJnU_+!64!=sjQw%!27(|Fq0dPU=S+4M)AD+_fSNfAy z^G(EMuz10;8%J~t4RXi1c}r7lA}GPf&7}Cd9N=AI{C2AR^9BKsy9x+|@Y?tahNJI2Uk90dh&l?jFy z@1<;u8T#fA)wcqXv|y;sh>D8t{j9JuJPNrchu}IhM@ED%O|y-7yz+%rRoM*{+}tep zh?uF!s!ch^0!qX?r)q(TRL==ncO?VzQ~bT0+cr#_w|$GD7auZq3zPG#GBlIN-)UI2 z55Wh>$N$=i-2#QDK?7cQX}2Y8H)dkZ7!2eN5DCy zTJ|KG?iBSsMy~R@Ols6<1P)gL|87JmC6cm&=E*beTdGvxE*VPIXb|Ps>@fhB7NS)E z=8%^}^*Q8wsKuH8N(0f00lmaxphZ*aYv5D%B(AJoYQR+-8LrNZq`|OFYLIb!g7D~& zncxZ%b3RfbXCs^`sn9#fnv<__muL!P4wx z#xZCD9tlC1q{J*awq~s!iJ{$-q+Q<_bEQ#RBa?LV5wnr8XW{OX@`%UX7<*4`@W_9D z)`>9j<#6B7?8^DjYUQR)8lwGSTBw3*Td)@`+&D`R=~Z0Wq3&8x7Y72GM|_iGvc1~s zS8+W?!@3XWh@=4{G@)Zku7opxCDo7Mi^!UtZ zs{%vyk+AI7Yz#)tr5Pe^M~J~~bb_vnZ@6Ki`6MaN24^`et0{R%L`e9kH;oXKz%<0K znSgD*Gu#VH$-TPmUFf-bbLy_((Y6;DmJ!juPOHqf7f!cJPDo=`H3iP#m5G!63rqKj zi3lBB|6j}V?|ICC5nH-$$hYa{t zL5cp(gulDrf9At~I^n;YKBhV6r}ta)!qb#-x-PTMujgFn*;?UK|Ti+~u3x zU}WZ%v1j8QvG;k%n`g{$!GOaF;5Ms zXbFQ*!P{p=+*4$T@=^)}n*~u`6-*rU0(0J0dXtbU-)XN5*t9n`8>pMH#iI5-G_9A_ zW)p7QZC%$s?d{qOXO4q{r;$uKJoUX#mGJg{s^caiUkePHDiNf<5(+ukg0}RX@X^74 zn;m$m3_$cNzO$b8cI0eQ9(J))k1q5J9mB`3zefC%oy1{ox`wAPFkdMCp2{Bj3pbF3 zy~W>O_Frek;j5vz1s;Guu9#;}Kw>~JUl{Yk98L3_)U@1dYUT;7nPgDp*%6UgAQk_) z+IvymGqv~iWYHgBiQbE``lTaa)$B>QN%p0J)R%7Uf^n7%+MgFXhLc-`ce1-5R!;;H z_3*8ShLKi#=a~}mxy^-!8uqmC5~b?qLlKbaBC7zNgS6Y*Rx{-}#T`AcJfZ@d+NwQg zVd+N9X^kkIkwzx2BpuZ+AaFGAiM_VuLX|{qMF(nud8+6DBt>dTSo)=Gr6@?OYRR}h zBe}|tX9)3#`b4DNMU_;Pl}WF-@7CpyMtk|BYs@-?ust|B3Ocyx*Wt+A2BU8|2WHAs zX2dmcdbc;jPgzss5uR6PBtu%h>5f*}6^|KwO@m>ma}L>l&kia%mxFOJ(6R22nwl%& z*NPqrO3at`{5)5#jq9rv;D@qOyAgoEDke8E-+>XKWZ6kVZ#}OEZk{*caF_hu37vyFYAGYulSVM#|h`uh(hG9A-toTk?_dHHMUG3Bqoqlmv|I z4waa=1k(;UTECq?GSOKw#$f#l0CvUUK<`Y^wa_W-w7PZdOFg4+idIz;AauE!RvGMB zb&%ZtV73fbYKeY&+6AfZ85tqF_qf>Xo7*rNZ>-<)P}$wuGQ9tBzOoWva(n(2qdeRH zW6yV?yQvYQw(Fnq0qPix!(-PMbHzI&hW?jR*&@PI?ai1(J8RTf#tw^6x^4r!b~tYA zRp&DgENXI0DY&b^Nf^Wq?Lg1e$bBc_l8h7oCvU_NTPpd~8py84!~tk0b>#Hz!rh>F zsrjwNxSf7hD@^a}zK>F5p7=RtON+zdA&3zEP@%CxH{X&`q4%ryn`;0RYX5Fa0^2WS zfDg0o@eP<8b__9yUv?=!aQ8*Vq=@#1ddR}~zuJEmT#UPLu*B;fvp;$Htui{)KIoGY zZGJSNr)FP$qfN6hk}j~n5q zUfF~<=#3D90qPsO?H}~%w){z>BW8}LgrW2t=;@=0#{1||H>-#^cuhAiq0!AFE7O-0 z@O$ty{#B7~dT^ZXA}o72CYh%WIP`P1#F+MOXLwmy^UVb6Zo$t9h%X)XPwdKOg{b`o zB1)=4-0K>{CUs(OD7RIfce%%QSB5fD`a}wAwOcthz6Ph#qpE1+UZH~xkPP^?Y6{)5 zn>cAxu;}k83~OjE_;z{aRS4y8;}mdPKK(NzG6621HE*%obt*n$LUT zEJNS7kLKwCR2Q?OzAVT^GuODNyH8j;1a`<4dct94>D}5T3t#lS@Oh~Nb^Vs7qzas4 za*B4khgRjsNr5FUPw(|1-!*c zn@ko>+tsX(_mbq|&iq+O6?ND&uYxOi#-1DUFeJf_7!x}idyV`Wgg&9Mg-WKZ>9d&5 ziJq54GQFRgH$ydRmSkR|YhYj#41+btmuy(r5lV+8pZu^_@kM^j{ ziUz{Jo|SIZnw8;iScgfnENWmivYoA+%#ySj8`X2BF`SvI+f9J#UWS%$&{Vx927S7S z!Jc(>C!TBoEwdM#d_>BClAL|xQ>WaA%HwP2hWn=ta>O_6QXkQ=UD3Y^5PcGd3WSS1 zZy^SyI~Pw=Q2JJF&R67!aJ!r`9-9kgnrh?3m>WDebnK;{veTjo3WeXUvQiAYfutuU zLBE5R8NAZ7h>z^G+oA2mrS48vT8pyUds-TXb>@0FV~z3S*tFS$*bR2&dz;ggZyd^i zhXoKqpUR}=n@M3K5VbWP3B|XyFJi2O)?#G`WNDGBNS}i0q{8eML+5fpZJq#Y5dPfGfXGTKF0#n=S`9{f-pL zk+g3_eP#B4#fJ3^itFYj;7@e7Rs~{J!;2~r^td-L&-G` z&5tN=XA1_-@>)q&yq(EQfQO7MDE$i4P>UB#MvL0EU93lFaH(FipU@W0J<3&WW|}(_ zr;clZ_61{%=fq0YA_syV#lpVkL_Jt`?qB1k2x@?_MH|T_(zN+2Hfb4JrPH+;OVjQ9 zFM;-Gj7EOtgN$AV_m2wQb7D-t`v;9<`Jo#o_}vh@f-EfDTpwoYhvlzom#Mwru+H|N zLDC=7;)7mbR?H_#E<~hg`S|ccMJH*71;Xoe4?iEzB7LJpFO5bP9wZ#0%_4leRghNY zG@Q=EU#R84_RRoMn{aMx%4F;A`pxoUvr?x@tpq~hNxxrL?2UD+@AI=le$zn`9V2eW z%U&H)FT*5K=co*%LT7}*tWhlXA3zL4b@dnzQ`J}CoZ}TQ+J46RTEN)lEX9pq)>^uG z0hV?Nx43f3GovAnBl`XPV#}kC#25zxzn_QzfuH}@}a}C}bSOyac1-cH`D`y~!fWFq% z;{welFo-q;Cx|xUA<_lD^)C0kje?o-U>s9DpV-E-*XZ0wK4{E2Vca=k?wz9by!C8qs*UaRD>~F@#Ypji5e#I( zARlUcO)(c;JlJh%$jw#6OC1be+ zRjG%xCS|MfrRZngj(y-5kA>Cev-5K1JCG?8o=+g+-<8eehEtLxNMm?5Up+f0r%70h zc@wj}&gfo(3PR{XRtjC?U02tXUPn1pmxzodO1+uNOmA~B2a+)IsXEP@E;Y9fG=giw zxyMUPV!3Q}sE3H~a`ekhApNpv5!5rW4)udE8jzq@UxE?fwLYJPKRURlf7aR`v(+h7d-BztK2D-b_Wt~Aw9%Zt@fV$^c%X+D7IT^-=gTl zsCw;#iza$6_?F1B;S{;mbWP=lVU%v50(?sv|-gg zXc9Z6yDOpdVF_`NX+JB24qKnq)~($LQ+QKz0|$)Jca5EHSo4#el8w4n)G5IZ$t<_U zSFl5w88v<;yZz!A$s~<+QSN@h_b0iEJS-f}UrO7*-&#DJ9RGO!