diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
| commit | a7abbf4ddc70068620e9f44b74dc162ce2e16ee2 (patch) | |
| tree | 74f66253717515d364ce74bd8275015c1f829cbc /src/lib/invoice | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
| parent | a1b9b647a6c4bda1f5db63879639d44543f9557e (diff) | |
Merged in refactor (pull request #1)
Refactor
Diffstat (limited to 'src/lib/invoice')
| -rw-r--r-- | src/lib/invoice/api/invoiceApi.js | 10 | ||||
| -rw-r--r-- | src/lib/invoice/api/invoicesApi.js | 10 | ||||
| -rw-r--r-- | src/lib/invoice/components/Invoice.jsx | 110 | ||||
| -rw-r--r-- | src/lib/invoice/components/Invoices.jsx | 177 | ||||
| -rw-r--r-- | src/lib/invoice/hooks/useInvoice.js | 13 | ||||
| -rw-r--r-- | src/lib/invoice/hooks/useInvoices.js | 15 | ||||
| -rw-r--r-- | src/lib/invoice/utils/invoices.js | 11 |
7 files changed, 346 insertions, 0 deletions
diff --git a/src/lib/invoice/api/invoiceApi.js b/src/lib/invoice/api/invoiceApi.js new file mode 100644 index 00000000..056df6c6 --- /dev/null +++ b/src/lib/invoice/api/invoiceApi.js @@ -0,0 +1,10 @@ +import odooApi from '@/core/api/odooApi' +import { getAuth } from '@/core/utils/auth' + +const invoiceApi = async ({ id }) => { + const auth = getAuth() + const dataInvoice = await odooApi('GET', `/api/v1/partner/${auth.partnerId}/invoice/${id}`) + return dataInvoice +} + +export default invoiceApi diff --git a/src/lib/invoice/api/invoicesApi.js b/src/lib/invoice/api/invoicesApi.js new file mode 100644 index 00000000..622fe6ee --- /dev/null +++ b/src/lib/invoice/api/invoicesApi.js @@ -0,0 +1,10 @@ +import odooApi from '@/core/api/odooApi' +import { getAuth } from '@/core/utils/auth' + +const invoicesApi = async ({ query }) => { + const auth = getAuth() + const dataInvoices = await odooApi('GET', `/api/v1/partner/${auth.partnerId}/invoice?${query}`) + return dataInvoices +} + +export default invoicesApi diff --git a/src/lib/invoice/components/Invoice.jsx b/src/lib/invoice/components/Invoice.jsx new file mode 100644 index 00000000..e34ad8c2 --- /dev/null +++ b/src/lib/invoice/components/Invoice.jsx @@ -0,0 +1,110 @@ +import Spinner from '@/core/components/elements/Spinner/Spinner' +import useInvoice from '../hooks/useInvoice' +import { downloadInvoice, downloadTaxInvoice } from '../utils/invoices' +import Divider from '@/core/components/elements/Divider/Divider' +import VariantGroupCard from '@/lib/variant/components/VariantGroupCard' +import currencyFormat from '@/core/utils/currencyFormat' + +const Invoice = ({ id }) => { + const { invoice } = useInvoice({ id }) + + if (invoice.isLoading) { + return ( + <div className='flex justify-center my-6'> + <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' /> + </div> + ) + } + + const address = invoice.data?.customer + let fullAddress = [] + if (address?.street) fullAddress.push(address.street) + if (address?.subDistrict?.name) fullAddress.push(address.subDistrict.name) + if (address?.district?.name) fullAddress.push(address.district.name) + if (address?.city?.name) fullAddress.push(address.city.name) + fullAddress = fullAddress.join(', ') + + return ( + invoice.data?.name && ( + <> + <div className='flex flex-col gap-y-4 p-4'> + <DescriptionRow label='No Invoice'>{invoice.data?.name}</DescriptionRow> + <DescriptionRow label='Status Transaksi'> + {invoice.data?.amountResidual > 0 ? ( + <span className='badge-solid-red'>Belum Lunas</span> + ) : ( + <span className='badge-solid-green'>Lunas</span> + )} + </DescriptionRow> + <DescriptionRow label='Purchase Order'> + {invoice.data?.purchaseOrderName || '-'} + </DescriptionRow> + <DescriptionRow label='Ketentuan Pembayaran'>{invoice.data?.paymentTerm}</DescriptionRow> + {invoice.data?.amountResidual > 0 && invoice.invoiceDate != invoice.invoiceDateDue && ( + <DescriptionRow label='Tanggal Jatuh Tempo'> + {invoice.data?.invoiceDateDue} + </DescriptionRow> + )} + <DescriptionRow label='Nama Sales'>{invoice.data?.sales}</DescriptionRow> + <DescriptionRow label='Tanggal Invoice'>{invoice.data?.invoiceDate}</DescriptionRow> + <div className='flex items-center'> + <p className='text-gray_r-11 leading-none'>Invoice</p> + <button + type='button' + className='btn-light py-1.5 px-3 ml-auto' + onClick={() => downloadInvoice(invoice.data)} + > + Download + </button> + </div> + <div className='flex items-center'> + <p className='text-gray_r-11 leading-none'>Faktur Pajak</p> + <button + type='button' + className='btn-light py-1.5 px-3 ml-auto' + onClick={() => downloadTaxInvoice(invoice.data)} + disabled={!invoice.data?.efaktur} + > + Download + </button> + </div> + </div> + + <Divider /> + + <div className='p-4 font-medium'>Detail Penagihan</div> + + <div className='flex flex-col gap-y-4 p-4 border-t border-gray_r-6'> + <DescriptionRow label='Nama'>{address?.name}</DescriptionRow> + <DescriptionRow label='Email'>{address?.email || '-'}</DescriptionRow> + <DescriptionRow label='No Telepon'>{address?.mobile || '-'}</DescriptionRow> + <DescriptionRow label='Alamat'>{fullAddress}</DescriptionRow> + </div> + + <Divider /> + + <div className='font-medium p-4'>Detail Produk</div> + + <div className='p-4 pt-0 flex flex-col gap-y-3'> + <VariantGroupCard + variants={invoice.data?.products} + buyMore + /> + <div className='flex justify-between mt-3 font-medium'> + <p>Total Belanja</p> + <p>{currencyFormat(invoice.data?.amountTotal)}</p> + </div> + </div> + </> + ) + ) +} + +const DescriptionRow = ({ children, label }) => ( + <div className='grid grid-cols-2'> + <span className='text-gray_r-11'>{label}</span> + <span className='text-right'>{children}</span> + </div> +) + +export default Invoice diff --git a/src/lib/invoice/components/Invoices.jsx b/src/lib/invoice/components/Invoices.jsx new file mode 100644 index 00000000..ab318a3c --- /dev/null +++ b/src/lib/invoice/components/Invoices.jsx @@ -0,0 +1,177 @@ +import { + CheckIcon, + ClockIcon, + EllipsisVerticalIcon, + MagnifyingGlassIcon +} from '@heroicons/react/24/outline' +import { toQuery } from 'lodash-contrib' +import _ from 'lodash' +import { useRouter } from 'next/router' +import { useState } from 'react' +import useInvoices from '../hooks/useInvoices' +import Spinner from '@/core/components/elements/Spinner/Spinner' +import Alert from '@/core/components/elements/Alert/Alert' +import Pagination from '@/core/components/elements/Pagination/Pagination' +import Link from '@/core/components/elements/Link/Link' +import currencyFormat from '@/core/utils/currencyFormat' +import BottomPopup from '@/core/components/elements/Popup/BottomPopup' +import { downloadInvoice, downloadTaxInvoice } from '../utils/invoices' + +const Invoices = () => { + const router = useRouter() + const { q = '', page = 1 } = router.query + + const limit = 10 + + const query = { + name: q, + offset: (page - 1) * limit, + limit + } + const { invoices } = useInvoices({ query }) + + const [inputQuery, setInputQuery] = useState(q) + const [toOthers, setToOthers] = useState(null) + + const pageCount = Math.ceil(invoices?.data?.saleOrderTotal / limit) + let pageQuery = _.omit(query, ['limit', 'offset']) + pageQuery = _.pickBy(pageQuery, _.identity) + pageQuery = toQuery(pageQuery) + + const handleSubmit = (e) => { + e.preventDefault() + router.push(`/my/invoices?q=${inputQuery}`) + } + + return ( + <div className='p-4 flex flex-col gap-y-4'> + <form + className='flex gap-x-3' + onSubmit={handleSubmit} + > + <input + type='text' + className='form-input' + placeholder='Cari Invoice...' + value={inputQuery} + onChange={(e) => setInputQuery(e.target.value)} + /> + <button + className='btn-light bg-transparent px-3' + type='submit' + > + <MagnifyingGlassIcon className='w-6' /> + </button> + </form> + + {invoices.isLoading && ( + <div className='flex justify-center my-4'> + <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' /> + </div> + )} + + {!invoices.isLoading && invoices.data?.invoices?.length === 0 && ( + <Alert + type='info' + className='text-center' + > + Tidak ada data invoice + </Alert> + )} + + {invoices.data?.invoices?.map((invoice, index) => ( + <div + className='p-4 shadow border border-gray_r-3 rounded-md' + key={index} + > + <div className='grid grid-cols-2'> + <Link href={`/my/invoice/${invoice.id}`}> + <span className='text-caption-2 text-gray_r-11'>No. Invoice</span> + <h2 className='text-red_r-11 mt-1'>{invoice.name}</h2> + </Link> + <div className='flex gap-x-1 justify-end'> + {invoice.amountResidual > 0 ? ( + <div className='badge-solid-red h-fit ml-auto'>Belum Lunas</div> + ) : ( + <div className='badge-solid-green h-fit ml-auto'>Lunas</div> + )} + <EllipsisVerticalIcon + className='w-5 h-5' + onClick={() => setToOthers(invoice)} + /> + </div> + </div> + <Link href={`/my/invoice/${invoice.id}`}> + <div className='grid grid-cols-2 text-caption-2 text-gray_r-11 mt-2 font-normal'> + <p>{invoice.invoiceDate}</p> + <p className='text-right'>{invoice.paymentTerm}</p> + </div> + <hr className='my-3' /> + <div className='grid grid-cols-2'> + <div> + <span className='text-caption-2 text-gray_r-11'>No. Purchase Order</span> + <p className='mt-1 font-medium text-gray_r-12'> + {invoice.purchaseOrderName || '-'} + </p> + </div> + <div className='text-right'> + <span className='text-caption-2 text-gray_r-11'>Total Invoice</span> + <p className='mt-1 font-medium text-gray_r-12'> + {currencyFormat(invoice.amountTotal)} + </p> + </div> + </div> + </Link> + {invoice.efaktur ? ( + <div className='badge-green h-fit mt-3 ml-auto flex items-center gap-x-0.5'> + <CheckIcon className='w-4 stroke-2' /> + Faktur Pajak + </div> + ) : ( + <div className='badge-red h-fit mt-3 ml-auto flex items-center gap-x-0.5'> + <ClockIcon className='w-4 stroke-2' /> + Faktur Pajak + </div> + )} + </div> + ))} + + <Pagination + pageCount={pageCount} + currentPage={parseInt(page)} + url={`/my/invoices${pageQuery}`} + className='mt-2 mb-2' + /> + + <BottomPopup + title='Lainnya' + active={toOthers} + close={() => setToOthers(null)} + > + <div className='flex flex-col gap-y-4 mt-2'> + <button + className='text-left disabled:opacity-60' + onClick={() => { + downloadInvoice(toOthers) + setToOthers(null) + }} + > + Download Invoice + </button> + <button + className='text-left disabled:opacity-60' + disabled={!toOthers?.efaktur} + onClick={() => { + downloadTaxInvoice(toOthers) + setToOthers(null) + }} + > + Download Faktur Pajak + </button> + </div> + </BottomPopup> + </div> + ) +} + +export default Invoices diff --git a/src/lib/invoice/hooks/useInvoice.js b/src/lib/invoice/hooks/useInvoice.js new file mode 100644 index 00000000..2de5e91e --- /dev/null +++ b/src/lib/invoice/hooks/useInvoice.js @@ -0,0 +1,13 @@ +import { useQuery } from 'react-query' +import invoiceApi from '../api/invoiceApi' + +const useInvoice = ({ id }) => { + const fetchInvoice = async () => await invoiceApi({ id }) + const { data, isLoading, refetch } = useQuery(`invoice-${id}`, fetchInvoice) + + return { + invoice: { data, isLoading, refetch } + } +} + +export default useInvoice diff --git a/src/lib/invoice/hooks/useInvoices.js b/src/lib/invoice/hooks/useInvoices.js new file mode 100644 index 00000000..061626e4 --- /dev/null +++ b/src/lib/invoice/hooks/useInvoices.js @@ -0,0 +1,15 @@ +import { useQuery } from 'react-query' +import invoicesApi from '../api/invoicesApi' +import _ from 'lodash-contrib' + +const useInvoices = ({ query }) => { + const queryString = _.toQuery(query) + const fetchInvoices = async () => await invoicesApi({ query: queryString }) + const { data, isLoading, refetch } = useQuery(`invoices-${queryString}`, fetchInvoices) + + return { + invoices: { data, isLoading, refetch } + } +} + +export default useInvoices diff --git a/src/lib/invoice/utils/invoices.js b/src/lib/invoice/utils/invoices.js new file mode 100644 index 00000000..221e53cf --- /dev/null +++ b/src/lib/invoice/utils/invoices.js @@ -0,0 +1,11 @@ +const downloadInvoice = (invoice) => { + const url = `${process.env.ODOO_HOST}/api/v1/download/invoice/${invoice.id}/${invoice.token}` + window.open(url, 'download') +} + +const downloadTaxInvoice = (invoice) => { + const url = `${process.env.ODOO_HOST}/api/v1/download/tax-invoice/${invoice.id}/${invoice.token}` + window.open(url, 'download') +} + +export { downloadInvoice, downloadTaxInvoice } |
