Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit29552c9

Browse files
authored
OBPIH-7541 Create UI for new reorder report (#5571)
1 parent6bda21a commit29552c9

File tree

13 files changed

+524
-66
lines changed

13 files changed

+524
-66
lines changed

‎grails-app/controllers/org/pih/warehouse/inventory/InventoryController.groovy‎

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -485,70 +485,7 @@ class InventoryController {
485485
}
486486

487487
defreorderReport() {
488-
Location location=Location.get(session.warehouse.id)
489-
def inventoryItems= dashboardService.getReorderReport(location)
490-
491-
String filename="Reorder report -"+ location.name+".csv"
492-
493-
response.setHeader("Content-disposition","attachment; filename=\"${filename}\"")
494-
495-
def hasRoleFinance= userService.hasRoleFinance(session.user)
496-
497-
def csv=""
498-
csv+='"'+"${warehouse.message(code: 'inventoryLevel.status.label')}"+'"'+","
499-
csv+='"'+"${warehouse.message(code: 'product.productCode.label')}"+'"'+","
500-
csv+='"'+"${warehouse.message(code: 'product.label')}"+'"'+","
501-
csv+='"'+"${warehouse.message(code: 'category.label')}"+'"'+","
502-
csv+='"'+"${warehouse.message(code: 'product.tags.label', default: 'Tags')}"+'"'+","
503-
csv+='"'+"${warehouse.message(code: 'product.unitOfMeasure.label')}"+'"'+","
504-
csv+='"'+"${warehouse.message(code: 'inventoryLevel.minQuantity.label')}"+'"'+","
505-
csv+='"'+"${warehouse.message(code: 'inventoryLevel.reorderQuantity.label')}"+'"'+","
506-
csv+='"'+"${warehouse.message(code: 'inventoryLevel.maxQuantity.label')}"+'"'+","
507-
csv+='"'+"${warehouse.message(code: 'inventory.averageMonthlyDemand.label', default: "Average Monthly Demand")}"+'"'+","
508-
csv+='"'+"${warehouse.message(code: 'inventory.quantityAvailable.label', default: 'Quantity Available')}"+'"'+","
509-
csv+='"'+"${warehouse.message(code: 'inventory.quantityToOrder.label', default: 'Quantity to Order')}"+'"'+","
510-
511-
if (hasRoleFinance) {
512-
csv+='"'+"${warehouse.message(code: 'product.unitCost.label', default: 'Unit Cost')}"+'"'+","
513-
csv+='"'+"${warehouse.message(code: 'inventory.expectedReorderCost.label', default: 'Expected Reorder Cost')}"+'"'+","
514-
}
515-
516-
csv+="\n"
517-
518-
inventoryItems.each {inventoryItem->
519-
def product= inventoryItem.productasProduct
520-
def inventoryLevel= inventoryItem.inventoryLevelasInventoryLevel
521-
def status= inventoryItem.status
522-
def statusMessage="${warehouse.message(code: 'enum.InventoryLevelStatusCsv.' + status)}"
523-
524-
def monthlyDemand= forecastingService.getDemand(location,null, product)?.monthlyDemand?:0
525-
526-
def quantityAvailableToPromise= inventoryItem.quantityAvailableToPromise?:0
527-
528-
def quantityToOrder= inventoryLevel?.maxQuantity==null?"No Max qty set - review based on monthly demand": inventoryLevel.maxQuantity- quantityAvailableToPromise
529-
530-
csv+='"'+ (statusMessage?:"")+'"'+","
531-
csv+='"'+ (product.productCode?:"")+'"'+","
532-
csv+=StringEscapeUtils.escapeCsv(product?.displayNameWithLocaleCode)+","
533-
csv+='"'+ (product?.category?.name?:"")+'"'+","
534-
csv+='"'+ (product?.tagsToString()?:"")+'"'+","
535-
csv+='"'+ (product?.unitOfMeasure?:"")+'"'+","
536-
csv+= (inventoryLevel?.minQuantity?:"")+","
537-
csv+= (inventoryLevel?.reorderQuantity?:"")+","
538-
csv+= (inventoryLevel?.maxQuantity?:"")+","
539-
csv+= monthlyDemand+","
540-
csv+= quantityAvailableToPromise+","
541-
csv+= quantityToOrder+","
542-
543-
if(hasRoleFinance) {
544-
csv+='"'+ (inventoryItem.unitCost?:"")+'"'+","
545-
csv+='"'+ (inventoryItem.expectedReorderCost?:"")+'"'+","
546-
}
547-
548-
csv+="\n"
549-
}
550-
551-
render(contentType:"text/csv",text:CSVUtils.prependBomToCsvString(csv))
488+
render(view:"/common/react")
552489
}
553490

554491
deflistQuantityOnHandZero() {

‎grails-app/i18n/messages.properties‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4830,3 +4830,17 @@ react.cycleCount.indicators.cardSubtitle.valueOfShrinkage.label=value of shrinka
48304830
react.cycleCount.indicators.cardInfo.productsInventoried.label=Number of products that were counted at least once during the time range.
48314831
react.cycleCount.indicators.cardInfo.inventoryAccuracy.label=Percentage of cycle counts with an equal count, compared to all cycle counts recorded during the time range (equal and non equal counts). This represents the share of inventory for which OpenBoxes inventory is accurately representing the physical inventory.
48324832
react.cycleCount.indicators.cardInfo.inventoryShrinkage.label=Inventory Shrinkage count is the number of products for which the overall inventory change over the time range selected is a negative adjustment (qty at the beginning of the time range is more than qty at the end). The financial inventory shrinkage is the equivalent of the inventory decrease for these products in USD.
4833+
react.report.reorder.header.label=Reorder Report
4834+
react.report.reorder.additionalInventoryLocations.label=Additional Inventory Locations
4835+
react.report.reorder.expiredStock.label=Expired Stock
4836+
react.report.reorder.filterProducts.label=Filter products
4837+
react.report.reorder.removeExpiredStock.label=Remove expired stock
4838+
react.report.reorder.includeExpiredStock.label=Include expired stock
4839+
react.report.reorder.removeExpiringWithin.label=Remove expiring within ${days} days
4840+
react.report.reorder.showAllProducts.label=Show all products
4841+
react.report.reorder.showProductsBelowReorder.label=Show products below reorder
4842+
react.report.reorder.showProductsBelowMaximum.label=Show products below maximum
4843+
react.report.reorder.showProductsBelowMinimum.label=Show products below minimum
4844+
react.report.reorder.category.label=Category
4845+
react.report.reorder.tags.label=Tags
4846+
react.report.reorder.loadTable.label=Load table

‎src/js/api/urls.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,7 @@ export const INDICATORS_REPORT = `${API}/reports/indicators`;
213213
exportconstINDICATORS_PRODUCTS_INVENTORIED=`${INDICATORS_REPORT}/productsInventoried`;
214214
exportconstINDICATORS_INVENTORY_SHRINKAGE=`${INDICATORS_REPORT}/inventoryShrinkage`;
215215
exportconstINDICATORS_INVENTORY_ACCURACY=`${INDICATORS_REPORT}/inventoryAccuracy`;
216+
217+
// INVENTORY
218+
exportconstINVENTORY_API=(id)=>`${API}/facilities/${id}/inventories`;
219+
exportconstREORDER_REPORT=(id)=>`${INVENTORY_API(id)}/reorderReport`;

‎src/js/components/Filter/FilterForm.jsx‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const FilterForm = ({
3737
showFilterVisibilityToggler,
3838
showSearchField,
3939
disableAutoUpdateFilterParams,
40+
onSubmit,
4041
})=>{
4142
const[amountFilled,setAmountFilled]=useState(0);
4243
const[filtersHidden,setFiltersHidden]=useState(hidden);
@@ -133,7 +134,10 @@ const FilterForm = ({
133134
return(
134135
<divclassName="filter-form">
135136
<Form
136-
onSubmit={updateFilterParams}
137+
onSubmit={(values)=>{
138+
updateFilterParams(values);
139+
onSubmit(values);
140+
}}
137141
initialValues={{ ...defaultValues}}
138142
render={({ values, handleSubmit, form})=>{
139143
formRef.current=form;
@@ -230,6 +234,7 @@ FilterForm.propTypes = {
230234
customSubmitButtonDefaultLabel:PropTypes.string,
231235
showFilterVisibilityToggler:PropTypes.bool,
232236
disableAutoUpdateFilterParams:PropTypes.bool,
237+
onSubmit:PropTypes.func,
233238
};
234239

235240
FilterForm.defaultProps={
@@ -248,4 +253,5 @@ FilterForm.defaultProps = {
248253
customSubmitButtonDefaultLabel:null,
249254
showFilterVisibilityToggler:true,
250255
disableAutoUpdateFilterParams:false,
256+
onSubmit:()=>{},
251257
};

‎src/js/components/Router.jsx‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ const AsyncCycleCountReporting = Loadable({
193193
loading:Loading,
194194
});
195195

196+
constAsyncReorderReport=Loadable({
197+
loader:()=>import('components/reporting/reorderReport/ReorderReport'),
198+
loading:Loading,
199+
});
200+
196201
constStockMovementList=(props)=>{
197202
constparsedSearchQuery=queryString.parse(props?.location?.search);
198203
constdirection=parsedSearchQuery?.direction?.toUpperCase();
@@ -233,6 +238,7 @@ const Router = (props) => {
233238
<MainLayoutRoutepath="**/stockMovement/list"component={StockMovementList}/>
234239
<MainLayoutRoutepath="**/stockMovement/createOutbound/:stockMovementId?"component={AsyncStockMovement}/>
235240
<MainLayoutRoutepath="**/stockMovement/importOutboundStockMovement"component={AsyncOutboundImport}/>
241+
<MainLayoutRoutepath="**/inventory/reorderReport"component={AsyncReorderReport}/>
236242
<MainLayoutRoutepath="**/inventory/cycleCount/count"component={AsyncCycleCountCountStep}/>
237243
<MainLayoutRoutepath="**/inventory/cycleCount/resolve"component={AsyncCycleCountResolveStep}/>
238244
<MainLayoutRoutepath="**/inventory/cycleCount/reporting"component={AsyncCycleCountReporting}/>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
importReactfrom'react';
2+
3+
importReorderReportFiltersfrom'components/reporting/reorderReport/ReorderReportFilters';
4+
importReorderReportHeaderfrom'components/reporting/reorderReport/ReorderReportHeader';
5+
importuseTranslationfrom'hooks/useTranslation';
6+
importPageWrapperfrom'wrappers/PageWrapper';
7+
8+
import'components/cycleCount/cycleCount.scss';
9+
10+
constReorderReport=()=>{
11+
useTranslation('report');
12+
13+
return(
14+
<PageWrapper>
15+
<ReorderReportHeader/>
16+
<divclassName="list-page-list-section">
17+
<ReorderReportFilters/>
18+
</div>
19+
</PageWrapper>
20+
);
21+
};
22+
23+
exportdefaultReorderReport;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
importFilterSelectFieldfrom'components/form-elements/FilterSelectField';
2+
import{
3+
getExpiredStockOptions,
4+
getFilterProductOptions,
5+
}from'consts/filterOptions';
6+
7+
constreorderReportFilterFields={
8+
additionalInventoryLocations:{
9+
type:FilterSelectField,
10+
attributes:{
11+
openOnClick:false,
12+
cache:false,
13+
multi:true,
14+
closeMenuOnSelect:false,
15+
blurInputOnSelect:false,
16+
valueKey:'id',
17+
labelKey:'label',
18+
filterElement:true,
19+
placeholder:'react.report.reorder.additionalInventoryLocations.label',
20+
defaultPlaceholder:'Additional Inventory Locations',
21+
showLabelTooltip:true,
22+
},
23+
getDynamicAttr:({
24+
locations,
25+
})=>({
26+
options:locations,
27+
}),
28+
},
29+
expiredStock:{
30+
type:FilterSelectField,
31+
attributes:{
32+
placeholder:'react.report.reorder.expiredStock.label',
33+
defaultPlaceholder:'Expired Stock',
34+
showLabelTooltip:true,
35+
filterElement:true,
36+
valueKey:'id',
37+
labelKey:'label',
38+
options:getExpiredStockOptions(),
39+
},
40+
},
41+
filterProducts:{
42+
type:FilterSelectField,
43+
attributes:{
44+
placeholder:'react.report.reorder.filterProducts.label',
45+
defaultPlaceholder:'Filter products',
46+
showLabelTooltip:true,
47+
filterElement:true,
48+
valueKey:'id',
49+
labelKey:'label',
50+
options:getFilterProductOptions(),
51+
},
52+
},
53+
categories:{
54+
type:FilterSelectField,
55+
attributes:{
56+
valueKey:'id',
57+
filterElement:true,
58+
placeholder:'react.report.reorder.category.label',
59+
defaultPlaceholder:'Category',
60+
showLabelTooltip:true,
61+
multi:true,
62+
closeMenuOnSelect:false,
63+
blurInputOnSelect:false,
64+
},
65+
getDynamicAttr:({ categories})=>({
66+
options:categories,
67+
}),
68+
},
69+
tags:{
70+
type:FilterSelectField,
71+
attributes:{
72+
valueKey:'id',
73+
filterElement:true,
74+
placeholder:'react.report.reorder.tags.label',
75+
defaultPlaceholder:'Tags',
76+
showLabelTooltip:true,
77+
multi:true,
78+
closeMenuOnSelect:false,
79+
blurInputOnSelect:false,
80+
},
81+
getDynamicAttr:({ tags})=>({
82+
options:tags,
83+
}),
84+
},
85+
};
86+
87+
exportdefaultreorderReportFilterFields;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
importReactfrom'react';
2+
3+
importFilterFormfrom'components/Filter/FilterForm';
4+
importreorderReportFilterFields
5+
from'components/reporting/reorderReport/ReorderReportFilterFields';
6+
importuseReorderReportFiltersfrom'hooks/reporting/useReorderReportFilters';
7+
importuseTranslatefrom'hooks/useTranslate';
8+
importListFilterFormWrapperfrom'wrappers/ListFilterFormWrapper';
9+
10+
constReorderReportFilters=()=>{
11+
consttranslate=useTranslate();
12+
13+
const{
14+
categories,
15+
tags,
16+
locations,
17+
defaultFilterValues,
18+
setFilterValues,
19+
downloadCsv,
20+
}=useReorderReportFilters({filterFields:reorderReportFilterFields});
21+
22+
return(
23+
<ListFilterFormWrapper>
24+
<FilterForm
25+
filterFields={reorderReportFilterFields}
26+
updateFilterParams={(values)=>{
27+
setFilterValues({ ...values});
28+
}}
29+
onSubmit={downloadCsv}
30+
defaultValues={defaultFilterValues}
31+
hidden={false}
32+
showFilterVisibilityToggler={false}
33+
showSearchField={false}
34+
allowEmptySubmit
35+
customSubmitButtonDefaultLabel="Load table"
36+
customSubmitButtonLabel="react.report.reorder.loadTable.label"
37+
formProps={{
38+
categories,
39+
tags,
40+
locations,
41+
translate,
42+
}}
43+
/>
44+
</ListFilterFormWrapper>
45+
);
46+
};
47+
48+
exportdefaultReorderReportFilters;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
importReactfrom'react';
2+
3+
importListTitlefrom'components/listPagesUtils/ListTitle';
4+
importHeaderWrapperfrom'wrappers/HeaderWrapper';
5+
6+
constReorderReportHeader=()=>(
7+
<HeaderWrapper>
8+
<ListTitlelabel={{
9+
id:'react.report.reorder.header.label',
10+
defaultMessage:'Reorder Report',
11+
}}
12+
/>
13+
</HeaderWrapper>
14+
);
15+
16+
exportdefaultReorderReportHeader;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp