@@ -62,35 +62,29 @@ public PageEnvelope<OnHandSummary> listOnHand(
6262 String code = pe != null ? pe .getCode () : ("P-" + e .getPartId ());
6363 String name = pe != null ? pe .getName () : null ;
6464 var partRef = new PartRef (e .getPartId (), code , name );
65- var last = com .gearfirst .warehouse .common .util .DateTimes .toKstString (e .getLastUpdatedAt ());
65+ var updatedAt = com .gearfirst .warehouse .common .util .DateTimes .toKstString (e .getLastUpdatedAt ());
6666 int onHand = e .getOnHandQty () == null ? 0 : e .getOnHandQty ();
6767 int safety = pe != null && pe .getSafetyStockQty () != null ? pe .getSafetyStockQty () : 0 ;
6868 boolean low = onHand < safety ;
69- items .add (new OnHandSummary (e .getWarehouseCode (), partRef , onHand , last , low , safety ));
69+ String supplier = e .getSupplierName ();
70+ Integer price = (pe != null ? pe .getPrice () : null );
71+ Integer priceTotal = (price == null ? null : Integer .valueOf (price .intValue () * onHand ));
72+ items .add (new OnHandSummary (e .getWarehouseCode (), partRef , onHand , updatedAt , low , safety , supplier , price , priceTotal ));
7073 }
71- // Filters: partKeyword (code|name), supplierName (part attribution ), qty range
74+ // Filters: partKeyword (code|name), supplierName (entity snapshot ), qty range
7275 var filtered = items .stream ()
7376 .filter (i -> partKeyword == null || partKeyword .isBlank ()
7477 || containsIgnoreCase (i .part ().code (), partKeyword )
7578 || containsIgnoreCase (i .part ().name (), partKeyword ))
76- .filter (i -> {
77- if (supplierName == null || supplierName .isBlank ()) {
78- return true ;
79- }
80- var pe = partMap .get (i .part ().id ());
81- var sname = (pe == null ? null : pe .getSupplierName ());
82- return containsIgnoreCase (sname , supplierName );
83- })
79+ .filter (i -> supplierName == null || supplierName .isBlank () || containsIgnoreCase (i .supplierName (), supplierName ))
8480 .filter (i -> minQty == null || i .onHandQty () >= minQty )
8581 .filter (i -> maxQty == null || i .onHandQty () <= maxQty )
8682 .toList ();
8783
88- // Sorting whitelist
84+ // Sorting whitelist (legacy default: partName, partCode)
8985 Comparator <OnHandSummary > cmp = Comparator
90- .comparing ((OnHandSummary s ) -> s .part ().name () == null ? "" : s .part ().name (),
91- String ::compareToIgnoreCase )
92- .thenComparing ((OnHandSummary s ) -> s .part ().code () == null ? "" : s .part ().code (),
93- String ::compareToIgnoreCase );
86+ .comparing ((OnHandSummary s ) -> s .part ().name () == null ? "" : s .part ().name (), String ::compareToIgnoreCase )
87+ .thenComparing ((OnHandSummary s ) -> s .part ().code () == null ? "" : s .part ().code (), String ::compareToIgnoreCase );
9488 if (sort != null && !sort .isEmpty ()) {
9589 cmp = buildComparator (sort , cmp );
9690 }
@@ -102,6 +96,86 @@ public PageEnvelope<OnHandSummary> listOnHand(
10296 return PageEnvelope .of (sorted .subList (from , Math .max (from , to )), page , size , total );
10397 }
10498
99+ @ Override
100+ @ Transactional (readOnly = true )
101+ public PageEnvelope <OnHandSummary > listOnHandAdvanced (
102+ String q ,
103+ Long partId ,
104+ String partCode ,
105+ String partName ,
106+ String warehouseCode ,
107+ String supplierName ,
108+ Integer minQty ,
109+ Integer maxQty ,
110+ int page ,
111+ int size ,
112+ List <String > sort
113+ ) {
114+ if (page < 0 || size < 1 || size > 200 ) {
115+ throw new BadRequestException (ErrorStatus .VALIDATION_REQUEST_MISSING_EXCEPTION );
116+ }
117+ if (minQty != null && maxQty != null && minQty > maxQty ) {
118+ throw new BadRequestException (ErrorStatus .VALIDATION_REQUEST_MISSING_EXCEPTION );
119+ }
120+ List <InventoryOnHandEntity > entities = (warehouseCode == null || warehouseCode .isBlank ())
121+ ? repo .findAll ()
122+ : repo .findAllByWarehouseCode (warehouseCode );
123+
124+ // Enrich with Part data
125+ var partIds = entities .stream ().map (InventoryOnHandEntity ::getPartId ).distinct ().toList ();
126+ var partMap = new HashMap <Long , PartEntity >();
127+ if (!partIds .isEmpty ()) {
128+ for (var p : parts .findAllById (partIds )) {
129+ partMap .put (p .getId (), p );
130+ }
131+ }
132+ var items = new ArrayList <OnHandSummary >(entities .size ());
133+ for (var e : entities ) {
134+ var pe = partMap .get (e .getPartId ());
135+ String code0 = pe != null ? pe .getCode () : ("P-" + e .getPartId ());
136+ String name0 = pe != null ? pe .getName () : null ;
137+ var partRef = new PartRef (e .getPartId (), code0 , name0 );
138+ var updatedAt = com .gearfirst .warehouse .common .util .DateTimes .toKstString (e .getLastUpdatedAt ());
139+ int onHand = e .getOnHandQty () == null ? 0 : e .getOnHandQty ();
140+ int safety = pe != null && pe .getSafetyStockQty () != null ? pe .getSafetyStockQty () : 0 ;
141+ boolean low = onHand < safety ;
142+ String supplier = e .getSupplierName ();
143+ Integer price = (pe != null ? pe .getPrice () : null );
144+ Integer priceTotal = (price == null ? null : Integer .valueOf (price .intValue () * onHand ));
145+ items .add (new OnHandSummary (e .getWarehouseCode (), partRef , onHand , updatedAt , low , safety , supplier , price , priceTotal ));
146+ }
147+
148+ String qn = q == null ? null : q .trim ();
149+ var filtered = items .stream ()
150+ .filter (i -> qn == null || qn .isBlank () ||
151+ containsIgnoreCase (i .part ().code (), qn ) ||
152+ containsIgnoreCase (i .part ().name (), qn ) ||
153+ containsIgnoreCase (i .supplierName (), qn ) ||
154+ containsIgnoreCase (i .warehouseCode (), qn ))
155+ .filter (i -> partId == null || java .util .Objects .equals (i .part ().id (), partId ))
156+ .filter (i -> partCode == null || partCode .isBlank () || containsIgnoreCase (i .part ().code (), partCode ))
157+ .filter (i -> partName == null || partName .isBlank () || containsIgnoreCase (i .part ().name (), partName ))
158+ .filter (i -> warehouseCode == null || warehouseCode .isBlank () || java .util .Objects .equals (i .warehouseCode (), warehouseCode ))
159+ .filter (i -> supplierName == null || supplierName .isBlank () || containsIgnoreCase (i .supplierName (), supplierName ))
160+ .filter (i -> minQty == null || i .onHandQty () >= minQty )
161+ .filter (i -> maxQty == null || i .onHandQty () <= maxQty )
162+ .toList ();
163+
164+ // Sorting: default updatedAt desc
165+ Comparator <OnHandSummary > cmp = Comparator .comparing (i -> i .updatedAt () == null ? "" : i .updatedAt ());
166+ // reverse for desc
167+ cmp = cmp .reversed ();
168+ if (sort != null && !sort .isEmpty ()) {
169+ cmp = buildComparator (sort , null );
170+ }
171+ var sorted = filtered .stream ().sorted (cmp ).toList ();
172+
173+ long total = sorted .size ();
174+ int from = Math .min (page * size , (int ) total );
175+ int to = Math .min (from + size , (int ) total );
176+ return PageEnvelope .of (sorted .subList (from , Math .max (from , to )), page , size , total );
177+ }
178+
105179 private Comparator <OnHandSummary > buildComparator (List <String > sort , Comparator <OnHandSummary > defaultCmp ) {
106180 Comparator <OnHandSummary > cmp = null ;
107181 for (String s : sort ) {
@@ -118,8 +192,14 @@ private Comparator<OnHandSummary> buildComparator(List<String> sort, Comparator<
118192 case "partCode" -> c = Comparator .comparing (i -> i .part ().code () == null ? "" : i .part ().code (),
119193 String ::compareToIgnoreCase );
120194 case "onHandQty" -> c = Comparator .comparingInt (OnHandSummary ::onHandQty );
195+ case "warehouseCode" -> c = Comparator .comparing (i -> i .warehouseCode () == null ? "" : i .warehouseCode (),
196+ String ::compareToIgnoreCase );
197+ case "supplierName" -> c = Comparator .comparing (i -> i .supplierName () == null ? "" : i .supplierName (),
198+ String ::compareToIgnoreCase );
121199 case "lastUpdatedAt" ->
122- c = Comparator .comparing (i -> i .lastUpdatedAt () == null ? "" : i .lastUpdatedAt ());
200+ c = Comparator .comparing (i -> i .updatedAt () == null ? "" : i .updatedAt ());
201+ case "updatedAt" ->
202+ c = Comparator .comparing (i -> i .updatedAt () == null ? "" : i .updatedAt ());
123203 default -> throw new BadRequestException (ErrorStatus .VALIDATION_REQUEST_MISSING_EXCEPTION );
124204 }
125205 if ("desc" .equals (dir )) {
0 commit comments