WIP/ Feature : Estimate & Receipt & Bill & Invoice

This commit is contained in:
elforjani3
2020-08-12 21:19:52 +02:00
parent 58c6b5466c
commit c86f0b29bf
66 changed files with 4288 additions and 535 deletions

View File

@@ -4,7 +4,7 @@ import t from 'store/types';
export const fetchBillsTable = ({ query = {} }) => {
return (dispatch, getState) =>
new Promise((resolve, rejcet) => {
const pageQuery = getState().bill.tableQuery;
const pageQuery = getState().bills.tableQuery;
dispatch({
type: t.BILLS_TABLE_LOADING,
@@ -12,7 +12,7 @@ export const fetchBillsTable = ({ query = {} }) => {
loading: true,
},
});
ApiService.get('bills', {
ApiService.get('purchases/bills', {
params: { ...pageQuery, ...query },
})
.then((response) => {
@@ -54,9 +54,9 @@ export const fetchBillsTable = ({ query = {} }) => {
export const deleteBill = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.delete(`bills/${id}`)
ApiService.delete(`purchases/bills/${id}`)
.then((response) => {
dispatch({ type: t.BILL_DELETE });
dispatch({ type: t.BILL_DELETE, payload: { id } });
resovle(response);
})
.catch((error) => {
@@ -71,7 +71,7 @@ export const submitBill = ({ form }) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post('bills', form)
ApiService.post('purchases/bills', form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
@@ -92,7 +92,7 @@ export const submitBill = ({ form }) => {
export const fetchBill = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.get(`bills/${id}`)
ApiService.get(`purchases/bills/${id}`)
.then((response) => {
dispatch({
type: t.BILL_SET,
@@ -117,7 +117,7 @@ export const editBill = (id, form) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post(`bills/${id}`, form)
ApiService.post(`purchases/bills/${id}`, form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,

View File

@@ -0,0 +1,102 @@
import { createReducer } from '@reduxjs/toolkit';
import { createTableQueryReducers } from 'store/queryReducers';
import t from 'store/types';
const initialState = {
items: {},
views: {},
loading: false,
currentViewId: -1,
tableQuery: {
page_size: 5,
page: 1,
},
};
const defaultBill = {
entries: [],
};
const reducer = createReducer(initialState, {
[t.BILL_SET]: (state, action) => {
const { id, bill } = action.payload;
const _bill = state.items[id] || {};
state.items[id] = { ...defaultBill, ..._bill, ...bill };
},
[t.BILLS_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = loading;
},
[t.BILLS_SET_CURRENT_VIEW]: (state, action) => {
state.currentViewId = action.currentViewId;
},
[t.BILLS_ITEMS_SET]: (state, action) => {
const { bills } = action.payload;
const _bills = {};
bills.forEach((bill) => {
_bills[bill.id] = {
...defaultBill,
...bill,
};
});
state.items = {
...state.items,
..._bills,
};
},
[t.BILL_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.items[id] !== 'undefined') {
delete state.items[id];
}
},
[t.BILLS_PAGE_SET]: (state, action) => {
const { customViewId, bills, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
state.views[viewId] = {
...view,
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: bills.map((i) => i.id),
},
},
};
},
[t.BILLS_PAGINATION_SET]: (state, action) => {
const { pagination, customViewId } = action.payload;
const mapped = {
pageSize: parseInt(pagination.pageSize, 10),
page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10),
};
const paginationMeta = {
...mapped,
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
pageIndex: Math.max(mapped.page - 1, 0),
};
state.views = {
...state.views,
[customViewId]: {
...(state.views?.[customViewId] || {}),
paginationMeta,
},
};
},
});
export default createTableQueryReducers('bills', reducer);

View File

@@ -1,6 +1,52 @@
import { createSelector } from '@reduxjs/toolkit';
import { pickItemsFromIds, paginationLocationQuery } from 'store/selectors';
const billByIdSelector = (state, props) => state.bills.items[props.billId];
const billTableQuery = (state) => {
return state.bills.tableQuery;
};
export const getBillById = () =>
createSelector(billByIdSelector, (_bill) => _bill);
export const getBillTableQuery = createSelector(
paginationLocationQuery,
billTableQuery,
(locationQuery, tableQuery) => {
return {
...locationQuery,
...tableQuery,
};
},
);
const billPageSelector = (state, props, query) => {
const viewId = state.bills.currentViewId;
return state.bills.views?.[viewId]?.pages?.[query.page];
};
const billItemsSelector = (state) => {
return state.bills.items;
};
export const getBillCurrentPageFactory = () =>
createSelector(billPageSelector, billItemsSelector, (billPage, billItems) => {
return typeof billPage === 'object'
? pickItemsFromIds(billItems, billPage.ids) || []
: [];
});
const billByIdSelector = (state, props) => {
return state.bills.items[props.billId];
};
export const getBillByIdFactory = () =>
createSelector(billByIdSelector, (bill) => {
return bill;
});
const billPaginationSelector = (state, props) => {
const viewId = state.bills.currentViewId;
return state.bills.views?.[viewId];
};
export const getBillPaginationMetaFactory = () =>
createSelector(billPaginationSelector, (billPage) => {
return billPage?.paginationMeta || {};
});

View File

@@ -8,6 +8,7 @@ export const submitEstimate = ({ form }) => {
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post('sales/estimates', form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
@@ -32,7 +33,7 @@ export const editEstimate = (id, form) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post(`estimates/${id}`, form)
ApiService.post(`sales/estimates/${id}`, form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
@@ -54,9 +55,12 @@ export const editEstimate = (id, form) => {
export const deleteEstimate = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.delete(`estimates/${id}`)
ApiService.delete(`sales/estimates/${id}`)
.then((response) => {
dispatch({ type: t.ESTIMATE_DELETE });
dispatch({
type: t.ESTIMATE_DELETE,
payload: { id },
});
resovle(response);
})
.catch((error) => {
@@ -68,8 +72,9 @@ export const deleteEstimate = ({ id }) => {
export const fetchEstimate = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.get(`estimate/${id}`)
ApiService.get(`sales/estimates/${id}`)
.then((response) => {
dispatch({
type: t.ESTIMATE_SET,
payload: {
@@ -90,36 +95,36 @@ export const fetchEstimate = ({ id }) => {
export const fetchEstimatesTable = ({ query = {} }) => {
return (dispatch, getState) =>
new Promise((resolve, rejcet) => {
const pageQuery = getState().estimates.tableQuery;
const pageQuery = getState().sales_estimates.tableQuery;
dispatch({
type: t.ESTIMATES_TABLE_LOADING,
payload: {
loading: true,
},
});
ApiService.get('estimates', {
ApiService.get('sales/estimates', {
params: { ...pageQuery, ...query },
})
.then((response) => {
// debugger;
dispatch({
type: t.ESTIMATES_PAGE_SET,
payload: {
estimates: response.data.estimates.results,
pagination: response.data.estimates.pagination,
sales_estimates: response.data.sales_estimates.results,
pagination: response.data.sales_estimates.pagination,
customViewId: response.data.customViewId || -1,
},
});
dispatch({
type: t.ESTIMATES_ITEMS_SET,
payload: {
estimates: response.data.estimates.results,
sales_estimates: response.data.sales_estimates.results,
},
});
dispatch({
type: t.ESTIMATES_PAGINATION_SET,
payload: {
pagination: response.data.estimates.pagination,
pagination: response.data.sales_estimates.pagination,
customViewId: response.data.customViewId || -1,
},
});

View File

@@ -8,27 +8,28 @@ const initialState = {
views: {},
loading: false,
tableQuery: {
page_size: 12,
page_size: 5,
page: 1,
},
currentViewId: -1,
};
const defaultEstimate = {
products: [],
entries: [],
};
const reducer = createReducer(initialState, {
[t.ESTIMATE_SET]: (state, action) => {
const { id, estiamate } = action.payload;
const { id, estimate } = action.payload;
const _estimate = state.items[id] || {};
state.items[id] = { ...defaultEstimate, ..._estimate, ...estiamate };
state.items[id] = { ...defaultEstimate, ..._estimate, ...estimate };
},
[t.ESTIMATES_ITEMS_SET]: (state, action) => {
const { estiamates } = action.payload;
const { sales_estimates } = action.payload;
const _estimates = {};
estiamates.forEach((estimate) => {
sales_estimates.forEach((estimate) => {
_estimates[estimate.id] = {
...defaultEstimate,
...estimate,
@@ -58,7 +59,7 @@ const reducer = createReducer(initialState, {
},
[t.ESTIMATES_PAGE_SET]: (state, action) => {
const { customViewId, estimates, pagination } = action.payload;
const { customViewId, sales_estimates, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
@@ -68,7 +69,7 @@ const reducer = createReducer(initialState, {
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: estimates.map((i) => i.id),
ids: sales_estimates.map((i) => i.id),
},
},
};
@@ -98,8 +99,8 @@ const reducer = createReducer(initialState, {
},
});
export default createTableQueryReducers('estimates', reducer);
export default createTableQueryReducers('sales_estimates', reducer);
export const getEstimateById = (state, id) => {
return state.estiamates.items[id];
return state.sales_estimates.items[id];
};

View File

@@ -1,44 +1,54 @@
import { createSelector } from '@reduxjs/toolkit';
import { pickItemsFromIds, paginationLocationQuery } from 'store/selectors';
const estimateTableQuery = (state) => state.estimates.tableQuery;
const estimateTableQuery = (state) => {
return state.sales_estimates.tableQuery;
};
export const getEstimatesTableQuery = createSelector(
paginationLocationQuery,
estimateTableQuery,
(location, query) => ({
...location,
...query,
}),
(locationQuery, tableQuery) => {
return {
...locationQuery,
...tableQuery,
};
},
);
const estimatesSelector = (state, props, query) => {
const viewId = state.estimates.currentViewId;
return state.estimates.views?.[viewId]?.pages?.[query.page];
const estimatesPageSelector = (state, props, query) => {
const viewId = state.sales_estimates.currentViewId;
return state.sales_estimates.views?.[viewId]?.pages?.[query.page];
};
const EstimateItemsSelector = (state) => state.estimates.items;
const estimateItemsSelector = (state) => state.sales_estimates.items;
export const getEstimateCurrentPage = () =>
createSelector(estimatesSelector, EstimateItemsSelector, (page, items) => {
return typeof page === 'object'
? pickItemsFromIds(items, page.ids) || []
: [];
});
export const getEstimateCurrentPageFactory = () =>
createSelector(
estimatesPageSelector,
estimateItemsSelector,
(estimatePage, estimateItems) => {
return typeof estimatePage === 'object'
? pickItemsFromIds(estimateItems, estimatePage.ids) || []
: [];
},
);
const estimateByIdSelector = (state, props) => state.estimates.items;
const estimateByIdSelector = (state, props) => {
return state.sales_estimates.items[props.estimateId];
};
export const getEstimateByIdFactory = () =>
createSelector(estimateByIdSelector, (estimate) => {
return estimate;
});
const paginationSelector = (state, props) => {
const viewId = state.estimates.currentViewId;
return state.estimates.views?.[viewId];
const estimatesPaginationSelector = (state, props) => {
const viewId = state.sales_estimates.currentViewId;
return state.sales_estimates.views?.[viewId];
};
export const getEstimatesPaginationMetaFactory = () =>
createSelector(paginationSelector, (estimatePage) => {
createSelector(estimatesPaginationSelector, (estimatePage) => {
return estimatePage?.paginationMeta || {};
});

View File

@@ -29,9 +29,12 @@ export const submitInvoice = ({ form }) => {
export const deleteInvoice = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.delete(`invoice/${id}`)
ApiService.delete(`sales/invoices/${id}`)
.then((response) => {
dispatch({ type: t.INVOICE_DELETE });
dispatch({
type: t.INVOICE_DELETE,
payload: { id },
});
resovle(response);
})
.catch((error) => {
@@ -46,7 +49,7 @@ export const editInvoice = (id, form) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post(`invoice/${id}`, form)
ApiService.post(`sales/invoices/${id}`, form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
@@ -64,39 +67,39 @@ export const editInvoice = (id, form) => {
});
});
};
export const fetchInvoicesTable = ({ query = {} }) => {
return (dispatch, getState) =>
new Promise((resolve, rejcet) => {
const pageQuery = getState().invoices.tableQuery;
export const fetchInvoicesTable = ({ query } = {}) => {
return (dispatch, getState) =>
new Promise((resolve, reject) => {
const pageQuery = getState().sales_invoices.tableQuery;
dispatch({
type: t.INVOICES_TABLE_LOADING,
payload: {
loading: true,
},
});
ApiService.get('invoices', {
ApiService.get('sales/invoices', {
params: { ...pageQuery, ...query },
})
.then((response) => {
dispatch({
type: t.INVOICES_PAGE_SET,
payload: {
invoices: response.data.invoices.results,
pagination: response.data.invoices.pagination,
sales_invoices: response.data.sales_invoices.results,
pagination: response.data.sales_invoices.pagination,
customViewId: response.data.customViewId || -1,
},
});
dispatch({
type: t.INVOICES_ITEMS_SET,
payload: {
invoices: response.data.invoices.results,
sales_invoices: response.data.sales_invoices.results,
},
});
dispatch({
type: t.INVOICES_PAGINATION_SET,
payload: {
pagination: response.data.invoices.pagination,
pagination: response.data.sales_invoices.pagination,
customViewId: response.data.customViewId || -1,
},
});
@@ -109,7 +112,7 @@ export const fetchInvoicesTable = ({ query = {} }) => {
resolve(response);
})
.catch((error) => {
rejcet(error);
reject(error);
});
});
};
@@ -117,13 +120,13 @@ export const fetchInvoicesTable = ({ query = {} }) => {
export const fetchInvoice = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.get(`invoices/${id}`)
ApiService.get(`sales/invoices/${id}`)
.then((response) => {
dispatch({
type: t.INVOICE_SET,
payload: {
id,
invoice: response.data.invoice,
sale_invoice: response.data.sale_invoice,
},
});
resovle(response);

View File

@@ -7,26 +7,99 @@ const initialState = {
items: {},
views: {},
loading: false,
currentViewId: -1,
tableQuery: {
page_size: 12,
page_size: 5,
page: 1,
},
currentViewId: -1,
};
const defaultInvoice = {
entires: [],
entries: [],
};
const reducer = createReducer(initialState, {
[t.INVOICE_SET]:(state,actio)=>{
[t.INVOICE_SET]: (state, action) => {
const { id, sale_invoice } = action.payload;
const _invoice = state.items[id] || {};
const {id,INVOICE_SET} = action.payload;
state.items[id] = { ...defaultInvoice, ..._invoice, ...sale_invoice };
},
}
[t.INVOICES_ITEMS_SET]: (state, action) => {
const { sales_invoices } = action.payload;
const _invoices = {};
sales_invoices.forEach((invoice) => {
_invoices[invoice.id] = {
...defaultInvoice,
...invoice,
};
});
state.items = {
...state.items,
..._invoices,
};
},
[t.INVOICES_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = loading;
},
[t.INVOICES_SET_CURRENT_VIEW]: (state, action) => {
state.currentViewId = action.currentViewId;
},
[t.INVOICE_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.items[id] !== 'undefined') {
delete state.items[id];
}
},
[t.INVOICES_PAGE_SET]: (state, action) => {
const { customViewId, sales_invoices, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
state.views[viewId] = {
...view,
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: sales_invoices.map((i) => i.id),
},
},
};
},
[t.INVOICES_PAGINATION_SET]: (state, action) => {
const { pagination, customViewId } = action.payload;
const mapped = {
pageSize: parseInt(pagination.pageSize, 10),
page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10),
};
const paginationMeta = {
...mapped,
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
pageIndex: Math.max(mapped.page - 1, 0),
};
state.views = {
...state.views,
[customViewId]: {
...(state.views?.[customViewId] || {}),
paginationMeta,
},
};
},
});
export default createTableQueryReducers('sales_invoices', reducer);
export const getInvoiceById = (state, id) => {
return state.sales_invoices.items[id];
};

View File

@@ -1,9 +1,54 @@
import { createSelector } from '@reduxjs/toolkit';
import { pickItemsFromIds, paginationLocationQuery } from 'store/selectors';
const invoiceByIdSelector = (state, props) =>
state.invoices.items[props.invoiceId];
const invoiceTableQuery = (state) => state.sales_invoices.tableQuery;
export const getInvoiceById = () =>
createSelector(invoiceByIdSelector, (_invoice) => {
return _invoice;
export const getInvoiceTableQuery = createSelector(
paginationLocationQuery,
invoiceTableQuery,
(locationQuery, tableQuery) => {
return {
...locationQuery,
...tableQuery,
};
},
);
const invoicesPageSelector = (state, props, query) => {
const viewId = state.sales_invoices.currentViewId;
return state.sales_invoices.views?.[viewId]?.pages?.[query.page];
};
const invoicesItemsSelector = (state) => {
return state.sales_invoices.items;
};
export const getInvoiceCurrentPageFactory = () =>
createSelector(
invoicesPageSelector,
invoicesItemsSelector,
(invoicePage, invoicesItems) => {
return typeof invoicePage === 'object'
? pickItemsFromIds(invoicesItems, invoicePage.ids) || []
: [];
},
);
const invoicesByIdSelector = (state, props) => {
return state.sales_invoices.items[props.invoiceId];
};
export const getInvoiecsByIdFactory = () =>
createSelector(invoicesByIdSelector, (invoice) => {
return invoice;
});
const invoicesPaginationSelector = (state, props) => {
const viewId = state.sales_invoices.currentViewId;
return state.sales_invoices.views?.[viewId];
};
export const getInvoicePaginationMetaFactory = () =>
createSelector(invoicesPaginationSelector, (invoicePage) => {
return invoicePage?.paginationMeta || {};
});

View File

@@ -28,9 +28,12 @@ export const submitReceipt = ({ form }) => {
export const deleteReceipt = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.delete(`receipts/${id}`)
ApiService.delete(`sales/receipts/${id}`)
.then((response) => {
dispatch({ type: t.RECEIPT_DELETE });
dispatch({
type: t.RECEIPT_DELETE,
payload: { id },
});
resovle(response);
})
.catch((error) => {
@@ -45,7 +48,7 @@ export const editReceipt = (id, form) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.delete(`receipt/${id}`, form)
ApiService.post(`sales/receipts/${id}`, form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
@@ -66,7 +69,7 @@ export const editReceipt = (id, form) => {
export const fetchReceipt = ({ id }) => {
return (dispatch) =>
new Promise((resovle, reject) => {
ApiService.get(`receipt/${id}`)
ApiService.get(`sales/receipts/${id}`)
.then((response) => {
dispatch({
type: t.RECEIPT_SET,
@@ -88,36 +91,35 @@ export const fetchReceipt = ({ id }) => {
export const fetchReceiptsTable = ({ query = {} }) => {
return (dispatch, getState) =>
new Promise((resolve, rejcet) => {
const pageQuery = getState().receipt.tableQuery;
const pageQuery = getState().sales_receipts.tableQuery;
dispatch({
type: t.RECEIPTS_TABLE_LOADING,
payload: {
loading: true,
},
});
ApiService.get('receipts', {
ApiService.get('sales/receipts', {
params: { ...pageQuery, ...query },
})
.then((response) => {
dispatch({
type: t.RECEIPTS_PAGE_SET,
payload: {
receipts: response.data.receipts.results,
pagination: response.data.receipts.pagination,
sales_receipts: response.data.sales_receipts.results,
pagination: response.data.sales_receipts.pagination,
customViewId: response.data.customViewId || -1,
},
});
dispatch({
type: t.RECEIPTS_ITEMS_SET,
payload: {
receipts: response.data.receipts.results,
sales_receipts: response.data.sales_receipts.results,
},
});
dispatch({
type: t.RECEIPTS_PAGINATION_SET,
payload: {
pagination: response.data.receipts.pagination,
pagination: response.data.sales_receipts.pagination,
customViewId: response.data.customViewId || -1,
},
});

View File

@@ -0,0 +1,103 @@
import { createReducer } from '@reduxjs/toolkit';
import { createTableQueryReducers } from 'store/queryReducers';
import t from 'store/types';
const initialState = {
items: {},
views: {},
loading: false,
tableQuery: {
page_size: 5,
page: 1,
},
currentViewId: -1,
};
const defaultReceipt = {
entries: [],
};
const reducer = createReducer(initialState, {
[t.RECEIPT_SET]: (state, action) => {
const { id, receipt } = action.payload;
const _receipt = state.items[id] || {};
state.items[id] = { ...defaultReceipt, ..._receipt, ...receipt };
},
[t.RECEIPTS_ITEMS_SET]: (state, action) => {
const { sales_receipts } = action.payload;
const _receipts = {};
sales_receipts.forEach((receipt) => {
_receipts[receipt.id] = {
...defaultReceipt,
...receipt,
};
});
state.items = {
...state.items,
..._receipts,
};
},
[t.RECEIPTS_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = loading;
},
[t.RECEIPT_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.items[id] !== 'undefined') {
delete state.items[id];
}
},
[t.RECEIPTS_SET_CURRENT_VIEW]: (state, action) => {
state.currentViewId = action.currentViewId;
},
[t.RECEIPTS_PAGE_SET]: (state, action) => {
const { customViewId, sales_receipts, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
state.views[viewId] = {
...view,
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: sales_receipts.map((i) => i.id),
},
},
};
},
[t.RECEIPTS_PAGINATION_SET]: (state, action) => {
const { pagination, customViewId } = action.payload;
const mapped = {
pageSize: parseInt(pagination.pageSize, 10),
page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10),
};
const paginationMeta = {
...mapped,
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
pageIndex: Math.max(mapped.page - 1, 0),
};
state.views = {
...state.views,
[customViewId]: {
...(state.views?.[customViewId] || {}),
paginationMeta,
},
};
},
});
export default createTableQueryReducers('sales_receipts', reducer);
export const getReceiptById = (state, id) => {
return state.receipts.items[id];
};

View File

@@ -0,0 +1,56 @@
import { createSelector } from '@reduxjs/toolkit';
import { pickItemsFromIds, paginationLocationQuery } from 'store/selectors';
const receiptsPageSelector = (state, props, query) => {
const viewId = state.sales_receipts.currentViewId;
return state.sales_receipts.views?.[viewId]?.pages?.[query.page];
};
const receiptItemsSelector = (state) => {
return state.sales_receipts.items;
};
export const getReceiptCurrentPageFactory = () =>
createSelector(
receiptsPageSelector,
receiptItemsSelector,
(receiptPage, receiptItems) => {
return typeof receiptPage === 'object'
? pickItemsFromIds(receiptItems, receiptPage.ids) || []
: [];
},
);
const receiptTableQuery = (state) => {
return state.sales_receipts.tableQuery;
};
export const getReceiptsTableQuery = createSelector(
paginationLocationQuery,
receiptTableQuery,
(locationQuery, tableQuery) => {
return {
...locationQuery,
...tableQuery,
};
},
);
const receiptByIdSelector = (state, props) => {
return state.sales_receipts.items[props.receiptId];
};
export const getReceiptByIdFactory = () =>
createSelector(receiptByIdSelector, (receipt) => {
return receipt;
});
const receiptsPaginationSelector = (state, props) => {
const viewId = state.sales_receipts.currentViewId;
return state.sales_receipts.views?.[viewId];
};
export const getReceiptsPaginationMetaFactory = () =>
createSelector(receiptsPaginationSelector, (receiptPage) => {
return receiptPage?.paginationMeta || {};
});

View File

@@ -18,7 +18,11 @@ import globalSearch from './search/search.reducer';
import exchangeRates from './ExchangeRate/exchange.reducer';
import globalErrors from './globalErrors/globalErrors.reducer';
import customers from './customers/customers.reducer';
import estimates from './Estimate/estimates.reducer';
import sales_estimates from './Estimate/estimates.reducer';
import sales_invoices from './Invoice/invoices.reducer';
import sales_receipts from './receipt/receipt.reducer';
import bills from './Bills/bills.reducer';
import vendors from './vendors/vendors.reducer';
export default combineReducers({
authentication,
@@ -39,5 +43,9 @@ export default combineReducers({
exchangeRates,
globalErrors,
customers,
estimates
sales_estimates,
sales_invoices,
sales_receipts,
bills,
vendors,
});

View File

@@ -22,6 +22,7 @@ import invoices from './Invoice/invoices.types';
import receipts from './receipt/receipt.type';
import bills from './Bills/bills.type';
import paymentReceives from './PaymentReceive/paymentReceive.type';
import vendors from './vendors/vendors.types';
export default {
...authentication,
@@ -48,4 +49,5 @@ export default {
...receipts,
...bills,
...paymentReceives,
...vendors,
};

View File

@@ -0,0 +1,118 @@
import ApiService from 'services/ApiService';
import t from 'store/types';
export const fetchVendorsTable = ({ query }) => {
return (dispatch, getState) =>
new Promise((resolve, reject) => {
const pageQuery = getState().vendors.tableQuery;
dispatch({
type: t.VENDORS_TABLE_LOADING,
payload: { loading: true },
});
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.get(`vendors`, { params: { ...pageQuery, ...query } })
.then((response) => {
dispatch({
type: t.VENDORS_PAGE_SET,
payload: {
vendors: response.data.vendors.results,
pagination: response.data.vendors.pagination,
customViewId: response.data.customViewId,
},
});
dispatch({
type: t.VENDORS_ITEMS_SET,
payload: {
vendors: response.data.vendors.results,
},
});
dispatch({
type: t.VENDORS_PAGINATION_SET,
payload: {
pagination: response.data.vendors.pagination,
customViewId: response.data.customViewId || -1,
},
});
dispatch({
type: t.VENDORS_TABLE_LOADING,
payload: { loading: false },
});
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
};
export const editVendor = ({ form, id }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post(`vendors/${id}`, form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
resolve(response);
})
.catch((error) => {
const { response } = error;
const { data } = response;
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
reject(data?.errors);
});
});
};
export const deleteVendor = ({ id }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.delete(`vendors/${id}`)
.then((response) => {
dispatch({ type: t.VENDOR_DELETE, payload: { id } });
resolve(response);
})
.catch((error) => {
reject(error.response.data.errors || []);
});
});
};
export const submitVendor = ({ form }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
ApiService.post('vendors', form)
.then((response) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
resolve(response);
})
.catch((error) => {
const { response } = error;
const { data } = response;
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
reject(data?.errors);
});
});
};

View File

@@ -0,0 +1,96 @@
import { createReducer } from '@reduxjs/toolkit';
import { createTableQueryReducers } from 'store/queryReducers';
import t from 'store/types';
const initialState = {
items: {},
views: {},
loading: false,
tableQuery: {
page_size: 5,
page: 1,
},
currentViewId: -1,
};
const reducer = createReducer(initialState, {
[t.VENDORS_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = loading;
},
[t.VENDORS_ITEMS_SET]: (state, action) => {
const { vendors } = action.payload;
const _vendors = {};
vendors.forEach((vendor) => {
_vendors[vendor.id] = {
...vendor,
};
});
state.items = {
...state.items,
..._vendors,
};
},
[t.VENDORS_PAGE_SET]: (state, action) => {
const { customViewId, vendors, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
state.views[viewId] = {
...view,
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: vendors.map((i) => i.id),
},
},
};
},
[t.VENDOR_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.items[id] !== 'undefined') {
delete state.items[id];
}
},
[t.VENDORS_SET_CURRENT_VIEW]: (state, action) => {
state.currentViewId = action.currentViewId;
},
[t.VENDORS_PAGINATION_SET]: (state, action) => {
const { pagination, customViewId } = action.payload;
const mapped = {
pageSize: parseInt(pagination.pageSize, 10),
page: parseInt(pagination.page, 10),
total: parseInt(pagination.total, 10),
};
const paginationMeta = {
...mapped,
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
pageIndex: Math.max(mapped.page - 1, 0),
};
state.views = {
...state.views,
[customViewId]: {
...(state.views?.[customViewId] || {}),
paginationMeta,
},
};
},
// [t.VENDOR_SET]: (state, action) => {
// const { id, vendor } = action.payload;
// const _venders = state.items[id] || {};
// state.items[id] = { ..._venders, ...vendor };
// },
});
export default createTableQueryReducers('vendors', reducer);

View File

@@ -0,0 +1,54 @@
import { createSelector } from '@reduxjs/toolkit';
import { pickItemsFromIds, paginationLocationQuery } from 'store/selectors';
const vendorsTableQuery = (state) => {
return state.vendors.tableQuery;
};
export const getVendorsTableQuery = createSelector(
paginationLocationQuery,
vendorsTableQuery,
(locationQuery, tableQuery) => {
return {
...locationQuery,
...tableQuery,
};
},
);
const vendorsPageSelector = (state, props, query) => {
const viewId = state.vendors.currentViewId;
return state.vendors.views?.[viewId]?.pages?.[query.page];
};
const vendorsItemsSelector = (state) => state.vendors.items;
export const getVendorCurrentPageFactory = () =>
createSelector(
vendorsPageSelector,
vendorsItemsSelector,
(vendorPage, vendorItems) => {
return typeof vendorPage === 'object'
? pickItemsFromIds(vendorItems, vendorPage.ids) || []
: [];
},
);
const vendorsPaginationSelector = (state, props) => {
const viewId = state.vendors.currentViewId;
return state.vendors.views?.[viewId];
};
export const getVendorsPaginationMetaFactory = () =>
createSelector(vendorsPaginationSelector, (vendorPage) => {
return vendorPage?.paginationMeta || {};
});
const vendorByIdSelector = (state, props) => {
return state.vendors.items[props.vendorId];
};
export const getEstimateByIdFactory = () =>
createSelector(vendorByIdSelector, (vendor) => {
return vendor;
});

View File

@@ -0,0 +1,11 @@
export default {
VENDORS_ITEMS_SET: 'VENDORS_ITEMS_SET',
VENDOR_SET: 'VENDOR_SET',
VENDORS_PAGE_SET: 'VENDORS_PAGE_SET',
VENDORS_TABLE_LOADING: 'VENDORS_TABLE_LOADING',
VENDORS_TABLE_QUERIES_ADD: 'VENDORS_TABLE_QUERIES_ADD',
VENDOR_DELETE: 'VENDOR_DELETE',
VENDORS_BULK_DELETE: 'VENDORS_BULK_DELETE',
VENDORS_PAGINATION_SET: 'VENDORS_PAGINATION_SET',
VENDORS_SET_CURRENT_VIEW: 'VENDORS_SET_CURRENT_VIEW',
};