add purchase for cut to pack locally

pull/23/head
Usama Khan 2025-05-13 05:24:46 +05:00
parent 4d235b2975
commit 88cfa11682
16 changed files with 462 additions and 197 deletions

View File

@ -2,13 +2,13 @@ package com.utopiaindustries.controller;
import com.utopiaindustries.auth.PurchaseOrderCTPRole;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.model.ctp.PurchaseOrderCTP;
import com.utopiaindustries.service.PurchaseOrderCTPService;
import com.utopiaindustries.util.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.time.LocalDate;
import java.util.List;
@ -37,7 +37,7 @@ public class PurchaseOrderCTPController {
model.addAttribute("purchaseOrder", purchaseOrderCTPService.getAllPurchaseOrderCtp(purchaseOrderCode, articleName, startDate.toString(), endDate.toString(), limit) );
model.addAttribute("startDate", startDate);
model.addAttribute("endDate", endDate);
return "job-card-list";
return "/purchaseOrder/purchase-order-list";
}
@GetMapping( "/new" )
@ -45,4 +45,46 @@ public class PurchaseOrderCTPController {
model.addAttribute("purchaseOrder", purchaseOrderCTPService.createNewPurchaseOrderCTP() );
return "/purchaseOrder/purchase-order-form";
}
@GetMapping( value = "/edit/{id}" )
public String showJobCardEditForm( @PathVariable("id") long id,
Model model ){
model.addAttribute("purchaseOrder", purchaseOrderCTPService.searchPurchaseOrderById( id ) );
return "/purchaseOrder/purchase-order-form";
}
/*
* draft
* */
@PostMapping( value ="/edit" , params = "user=draft" )
public String saveJobCard( @ModelAttribute PurchaseOrderCTP purchaseOrderCTP,
RedirectAttributes redirectAttributes,
Model model ){
try {
purchaseOrderCTP.setStatus( PurchaseOrderCTP.Status.DRAFT.name() );
purchaseOrderCTPService.save( purchaseOrderCTP );
redirectAttributes.addFlashAttribute("success", "Successfully saved!" );
} catch ( Exception ex ){
redirectAttributes.addFlashAttribute("error", ex.getMessage() );
}
return "redirect:/purchase-order";
}
@PostMapping( value ="/edit" , params = "user=post" )
public String postJobCard( @ModelAttribute PurchaseOrderCTP purchaseOrderCTP,
RedirectAttributes redirectAttributes,
Model model ){
try {
purchaseOrderCTP.setStatus( PurchaseOrderCTP.Status.POSTED.name() );
purchaseOrderCTPService.save( purchaseOrderCTP );
redirectAttributes.addFlashAttribute("success", "Successfully saved!" );
} catch ( Exception ex ){
redirectAttributes.addFlashAttribute("error", ex.getMessage() );
}
return "redirect:/purchase-order";
}
}

View File

@ -1,7 +1,9 @@
package com.utopiaindustries.dao.ctp;
import com.utopiaindustries.dao.uind.PurchaseOrderRowMapper;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.model.ctp.PurchaseOrderCTP;
import com.utopiaindustries.model.uind.PurchaseOrder;
import com.utopiaindustries.util.KeyHolderFunctions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@ -36,6 +38,7 @@ public class PurchaseOrderCTPDao {
"status = VALUES(status)",
TABLE_NAME);
private final String SELECT_BY_LIMIT = String.format( "SELECT * FROM %s WHERE created_by = :created_by ORDER BY id ASC limit :limit", TABLE_NAME );
private final String SELECT_BY_TERM = String.format( "SELECT * FROM %s WHERE purchase_order_code LIKE :term limit 100 offset 0", TABLE_NAME );
// prepare query params
@ -109,4 +112,13 @@ public class PurchaseOrderCTPDao {
params.addValue("limit", limit.intValue());
return namedParameterJdbcTemplate.query( SELECT_ALL_QUERY_WITH_LIMIT, params, new PurchaseOrderCTPRowMapper() );
}
/*
* find by term
* */
public List<PurchaseOrderCTP> findByTerm(String term ){
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("term", "%" + term + "%" );
return namedParameterJdbcTemplate.query( SELECT_BY_TERM, params, new PurchaseOrderCTPRowMapper() );
}
}

View File

@ -9,5 +9,6 @@ public enum Roles {
ROLE_QUALITY_CONTROL,
ROLE_FINISHING,
ROLE_PACKAGING,
ROLE_REPORTING
ROLE_REPORTING,
ROLE_PURCHASE_ORDER
}

View File

@ -1,6 +1,8 @@
package com.utopiaindustries.restcontroller;
import com.utopiaindustries.model.ctp.PurchaseOrderCTP;
import com.utopiaindustries.model.uind.PurchaseOrder;
import com.utopiaindustries.service.PurchaseOrderCTPService;
import com.utopiaindustries.service.PurchaseOrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -14,9 +16,11 @@ import java.util.List;
public class PurchaseOrderRestController {
private final PurchaseOrderService purchaseOrderService;
private final PurchaseOrderCTPService purchaseOrderCTPService;
public PurchaseOrderRestController(PurchaseOrderService purchaseOrderService) {
public PurchaseOrderRestController(PurchaseOrderService purchaseOrderService, PurchaseOrderCTPService purchaseOrderCTPService) {
this.purchaseOrderService = purchaseOrderService;
this.purchaseOrderCTPService = purchaseOrderCTPService;
}
/*
@ -26,4 +30,12 @@ public class PurchaseOrderRestController {
public List<PurchaseOrder> findByTerm(@RequestParam("term") String term ) {
return purchaseOrderService.findByTerm( term );
}
/*
* search by term in ctp purchase order table
* */
@GetMapping( "/ctp-po-search" )
public List<PurchaseOrderCTP> findByTermInCtpPurchaseOrderTable(@RequestParam("term") String term ) {
return purchaseOrderCTPService.findByTerm( term );
}
}

View File

@ -71,11 +71,7 @@ public class InventoryAccountService {
}
public List<InventoryAccount> findInventoryAccounts(){
List<InventoryAccount> accounts = inventoryAccountDAO.findAll();
for( InventoryAccount account : accounts ){
account.setLocationTitle( locationSiteDAO.find( account.getLocationSiteId() ).getTitle() );
}
return accounts;
return inventoryAccountDAO.findAll();
}
public List<InventoryAccount> findInventoryAccountsByFilter(String id, String title, String active, String createdBy, String startDate, String endDate,

View File

@ -149,20 +149,7 @@ public class JobCardService {
for (JobCardItem item : jobCard.getItems()) {
item.setJobCardId(jobCardId);
long itemId = jobCardItemDAO.save(item);
for (CutPiece cutPiece : item.getCutPieces()) {
cutPiece.setJobCardItemId(itemId);
if (!skuCutPiecesDAO.doesExist(cutPiece.getType(), item.getSku())){
SkuCutPieces skuCutPieces = new SkuCutPieces();
skuCutPieces.setType(cutPiece.getType());
skuCutPieces.setSku(item.getSku());
//save cut-piece for sku next time fetch
skuCutPiecesDAO.save(skuCutPieces);
}
cutPieces.add(cutPiece);
}
}
// save all pieces
cutPieceDAO.saveAll(cutPieces);
}
}

View File

@ -2,6 +2,7 @@ package com.utopiaindustries.service;
import com.utopiaindustries.dao.ctp.PurchaseOrderCTPDao;
import com.utopiaindustries.model.ctp.*;
import com.utopiaindustries.model.uind.PurchaseOrder;
import com.utopiaindustries.querybuilder.ctp.JobCardQueryBuilder;
import com.utopiaindustries.querybuilder.ctp.PurchaseOrderCTPQueryBuilder;
import com.utopiaindustries.util.StringUtils;
@ -32,7 +33,7 @@ public class PurchaseOrderCTPService {
}
/*
* create new job card
* create new purchase
* */
public PurchaseOrderCTP createNewPurchaseOrderCTP() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@ -43,27 +44,27 @@ public class PurchaseOrderCTPService {
}
/*
* save card
* save purchase order for ctp
* */
@Transactional( rollbackFor = Exception.class )
public void save(PurchaseOrderCTP purchaseOrderCTP) {
purchaseOrderCTPDao.save(purchaseOrderCTP);
}
public List<PurchaseOrderCTP> getAllPurchaseOrderCtp(String purchaseOrderCode, String articleName, String StartDate, String EndDate, Long limit) {
public List<PurchaseOrderCTP> getAllPurchaseOrderCtp(String purchaseOrderCode, String articleName, String startDate, String endDate, Long limit) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
List<PurchaseOrderCTP> list = new ArrayList<>();
String createdBy = authentication.getName();
if( limit == null ){
limit = 100L;
}
if( !StringUtils.isAnyNotNullOrEmpty(purchaseOrderCode, articleName) ){
if(StringUtils.isAnyNotNullOrEmpty(purchaseOrderCode, articleName,startDate,endDate) ){
for (GrantedAuthority role : authentication.getAuthorities()){
if (role.toString().equals("ROLE_ADMIN")){
createdBy = "";
}
}
String query = PurchaseOrderCTPQueryBuilder.buildQuery(purchaseOrderCode, articleName, createdBy, StartDate, EndDate, limit );
String query = PurchaseOrderCTPQueryBuilder.buildQuery(purchaseOrderCode, articleName, createdBy, startDate, endDate, limit );
System.out.println( query );
list = purchaseOrderCTPDao.findByQuery( query );
}else {
@ -72,4 +73,8 @@ public class PurchaseOrderCTPService {
return list;
}
public List<PurchaseOrderCTP> findByTerm(String term ){
return purchaseOrderCTPDao.findByTerm( term );
}
}

View File

@ -219,6 +219,10 @@
data: {
jobCard: {},
items: [],
purchaseOrderID:0,
articleName: '',
purchaseOrderQuantity: 0,
purchaseOrderCode: '',
},
methods: {
addItem: function (e) {
@ -259,10 +263,19 @@
}
}
return false;
}, onPoSelect(id,purchaseOrder) {
this.purchaseOrderID = id,
this.articleName = purchaseOrder.articleName,
this.purchaseOrderQuantity = purchaseOrder.purchaseOrderQuantity,
this.purchaseOrderCode = purchaseOrder.purchaseOrderCode
}
},
mounted: function () {
this.jobCard = window.ctp.jobCard;
this.purchaseOrderID = this.jobCard.purchaseOrderId,
this.articleName = this.jobCard.articleName,
this.purchaseOrderQuantity = this.jobCard.poQuantity,
this.purchaseOrderCode = this.jobCard.purchaseOrderTitle
this.items = this.jobCard.items;
}

View File

@ -3592,6 +3592,48 @@ if ( typeof Vue !== 'undefined' ) {
});
/*
* search po
* */
Vue.component('search-ctp-po',{
mixins: [searchComponentMixin],
data: {
purchaseOrderCode: '',
},
methods : {
getSearchUrl : function () {
return `/ctp/rest/purchase-orders/ctp-po-search?term=${encodeURIComponent( this.list.term )}`
},
getEmittedEventName: function() {
return 'select-po';
},
getTitle: function( po ) {
this.purchaseOrderCode = po.purchaseOrderCode;
return this.purchaseOrderCode;
}
},
props: {
labelText: {
default: 'Search PO '
},
titleFieldName: {
default: 'poCode'
},
idFieldName: {
default: 'poId'
},
codeFieldName : {
default : 'poCode'
},
received : {
default : false
},
inputMode: {
default : 'none'
},
}
})
Vue.component('search-item', {
props: {

View File

@ -31,10 +31,10 @@
<img th:src="@{/img/utopia-industries-white.svg}" class="page-header__logo" alt="Utopia Industries">
</a>
<ul class="navbar-nav">
<!-- <li class="nav-item" sec:authorize="hasAnyRole('ROLE_PURCHASE_ORDER', 'ROLE_ADMIN')">-->
<!-- <a th:href="@{/purchase-order/}" class="nav-link"-->
<!-- th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/purchase-order') ? 'active' : ''}">Purchase Order</a>-->
<!-- </li>-->
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_PURCHASE_ORDER', 'ROLE_ADMIN')">
<a th:href="@{/purchase-order/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/purchase-order') ? 'active' : ''}">Purchase Order</a>
</li>
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_JOB_CARD', 'ROLE_ADMIN')">
<a th:href="@{/job-cards/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/job-cards') ? 'active' : ''}">Job Cards</a>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml"
xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:ctp="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head('Home Page')"></head>
<body>
<div class="container-fluid">
@ -17,6 +18,13 @@
<input hidden="hidden" th:field="*{createdBy}">
<input hidden="hidden" th:field="*{status}">
<input hidden="hidden" th:field="*{inventoryStatus}">
<!-- Hidden Inputs for Dynamic Values -->
<input type="hidden" name="articleName" :value="articleName">
<input type="hidden" name="poQuantity" :value="purchaseOrderQuantity">
<input type="hidden" name="purchaseOrderTitle" :value="purchaseOrderCode">
<input type="hidden" name="purchaseOrderId" :value="purchaseOrderID">
<div class="bg-light p-3 mb-3">
<h6 class="mb-3">Info</h6>
<div class="form-row">
@ -34,28 +42,35 @@
</div>
<div class="col-sm-3 form-group">
<label>Article Name</label>
<input class="form-control" th:field="*{articleName}" required>
<!-- Dynamically show articleName -->
<span class="form-control">{{ articleName || jobCard.articleName }}</span>
</div>
</div>
<div class="form-row">
<div class="col-sm-3 form-group">
<label>Purchase Order</label>
<input type="text" class="form-control" th:field="*{purchaseOrderId}" required>
</div>
<search-ctp-po
v-bind:id-field-name="'poID'"
v-on:select-po="onPoSelect"
v-bind:required="false"
v-bind:selected="purchaseOrderCode">
</search-ctp-po>
<div class="col-sm-3 form-group">
<label>PO Quantity</label>
<input type="number" class="form-control" th:field="*{poQuantity}" required>
<!-- Dynamically show PO quantity -->
<span class="form-control">{{ purchaseOrderQuantity || jobCard.poQuantity }}</span>
</div>
<div class="col-sm-3 form-group" th:with="title=*{locationTitle},id=*{locationSiteId}">
<location-site-search th:attr="id=${id},title=${title}"
v-bind:id-field-name="'locationSiteId'">
<location-site-search th:attr="id=${id},title=${title}" v-bind:id-field-name="'locationSiteId'">
</location-site-search>
</div>
<div class="col-sm-3 form-group">
<label>Generated Date</label>
<span class="form-control" ctp:formatdatetime="*{createdAt}" readonly>
<!-- Use Thymeleaf to format datetime -->
<span class="form-control" ctp:formatdatetime="*{createdAt}" readonly></span>
</div>
</div>
<div class="form-row">
<div class="col-sm-6 form-group">
<label>Description*</label>
@ -85,8 +100,8 @@
</form>
<script th:inline="javascript">
window.ctp.jobCard = [[${jobCard}]];
window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
window.ctp.types = [[${cutPieceTypes}]];
window.ctp.accounts = [[${accounts}]];
</script>
<script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/job-card-form.js}"></script>

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml"
xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:ctp="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head('Home Page')"></head>
<body>
<div class="container-fluid">
@ -7,26 +8,45 @@
<main class="row page-main">
<div class="col-sm" th:fragment="cardFragment">
<div th:replace="_notices :: page-notices"></div>
<form th:action="@{ ${purchaseOrderCTP.id} ? ('/purchase-order/edit/' + ${purchaseOrderCTP.id}) : '/purchase-order/edit' }"
<form th:action="${purchaseOrder.id} != null ? @{/purchase-order/edit/(id=${purchaseOrder.id})} : @{/purchase-order/edit}"
method="POST"
th:object="${purchaseOrderCTP}"
id="purchaseOrderApp">
<input hidden="hidden" th:field="*{id}">
<input hidden="hidden" th:field="*{order}">
th:object="${purchaseOrder}"
id="jobCardApp">
<div class="bg-light p-3 mb-3">
<h6 class="mb-3">Info</h6>
<input hidden="hidden" th:field="${purchaseOrder.id}">
<input hidden="hidden" th:field="${purchaseOrder.createdAt}">
<input hidden="hidden" th:field="${purchaseOrder.createdBy}">
<div class="form-row">
<div class="col-sm-3 form-group">
<label>Job Order</label>
<input type="number" class="form-control" th:field="*{jobOrderId}" required>
<label>Purchase Order Code</label>
<input class="form-control" th:field="${purchaseOrder.purchaseOrderCode}" required>
</div>
<div class="col-sm-3 form-group">
<label>Purchase Order Quantity</label>
<input class="form-control" th:field="${purchaseOrder.purchaseOrderQuantity}" required>
</div>
<div class="col-sm-3 form-group">
<label>Required Quantity</label>
<input class="form-control" th:field="${purchaseOrder.purchaseOrderQuantityRequired}" required>
</div>
<div class="col-sm-3 form-group">
<label>Article Name</label>
<input type="text" class="form-control" th:field="${purchaseOrder.articleName}" required>
</div>
</div>
</div>
<div>
<button class="btn btn-secondary" type="submit" name="user" value="draft" v-bind:disabled="hasEmptyItems()">Save Draft</button>
<button class="btn btn-primary" type="submit" name="user" value="post" v-bind:disabled="hasEmptyItems()">Post</button>
<a th:href="@{/job-cards}" class="btn btn-light">Cancel</a>
<button class="btn btn-secondary" type="submit" name="user" value="draft"
v-bind:disabled="hasEmptyItems()">
Save Draft
</button>
<button class="btn btn-primary" type="submit" name="user" value="post"
v-bind:disabled="hasEmptyItems()">
Post
</button>
<a th:href="@{/purchase-order}" class="btn btn-light">Cancel</a>
</div>
</form>

View File

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml"
xmlns:uind="http://www.w3.org/1999/xhtml" xmlns:ctp="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head('Purchase Order')"></head>
<body>
<div class="container-fluid">
<header class="row page-header" th:replace="_fragments :: page-header"></header>
<main class="row page-main">
<!-- sidebar starts -->
<aside class="col-sm-2" th:replace="/purchaseOrder/purchase-order-sidebar :: sidebar"></aside>
<!-- sidebar ends -->
<!--header starts-->
<div class="col-sm">
<div th:replace="_notices :: page-notices"></div>
<div class="mb-4 d-flex justify-content-between">
<h3>Job Cards</h3>
<a th:href="@{/purchase-order/new}" class="btn btn-primary">Add New</a>
</div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<!-- Show table if purchaseOrder is not null and not empty -->
<table th:if="${purchaseOrder != null and !purchaseOrder.isEmpty()}" class="table table-striped font-sm" >
<thead>
<tr>
<th>PO Code</th>
<th>PO Quantity</th>
<th>Required Quantity</th>
<th>Article Name</th>
<th>Created At</th>
<th>Created By</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="order : ${purchaseOrder}" th:object="${purchaseOrder}">
<td th:text="${order.purchaseOrderCode}"></td>
<td th:text="${order.purchaseOrderQuantity}"></td>
<td th:text="${order.purchaseOrderQuantityRequired}"></td>
<td th:text="${order.articleName}"></td>
<td ctp:formatdatetime="${order.createdAt}"></td>
<td th:text="${order.createdBy}"></td>
<td>
<span class="badge font-sm" th:classappend="'badge-' + ${order.status}" th:if="${order.status}" th:text="${order.status}"></span>
<span th:unless="${order.status}">-</span>
</td>
<td>
<th:block >
<a th:href="@{'/purchase-order/edit/' + ${order.id}}" class="btn btn-sm btn-secondary" title="Edit">
<i class="bi bi-pencil"></i>
</a>
</th:block>
</td>
</tr>
</tbody>
</table>
<!-- Show message if purchaseOrder is null or empty -->
<h4 th:if="${purchaseOrder == null or purchaseOrder.isEmpty()}">No cards found.</h4>
</div>
</main>
</div>
<div th:replace="_fragments :: page-footer-scripts"></div>
</body>
</html>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head('Home Page')"></head>
<body>
<!-- sidebar starts -->
<aside class="col-sm-2" th:fragment="sidebar">
<div class="page-filters-sidebar">
<form th:action="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}">
<h5 class="mb-4">Refine Your Search</h5>
<div class="form-group">
<label>PO Code</label>
<input type="text" class="form-control" name="purchaseOrderCode" maxlength="100" th:value="${param['purchaseOrderCode']}">
</div>
<div class="form-group">
<label>Article Name</label>
<input type="text" class="form-control" name="articleName" maxlength="100" th:value="${param['articleName']}">
</div>
<div class="form-group">
<label>From Date</label>
<input type="date" class="form-control" name="created-start-date" th:value="${param['created-start-date'] ?: startDate }" >
</div>
<div class="form-group">
<label>To Date</label>
<input type="date" class="form-control" name="created-end-date" th:value="${param['created-end-date'] ?: endDate}" >
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="limit"
th:value="${param['limits'] ?: 100}">
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">
<a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"
class="btn btn-secondary btn-block">Reset</a>
</form>
</div>
</aside>
<!-- sidebar ends -->
<div th:fragment="page-footer-scripts">
<script th:src="@{/js/vendor/lazyload-db.js}"></script>
<script th:src="@{/js/main.js}"></script>
</div>
</body>
</html>

View File

@ -10,25 +10,37 @@
<main class="row page-main">
<aside class="col-sm-2" th:replace="/reporting/inventory-summary-sidebar :: sidebar"></aside>
<div class="col-sm">
<div class="col-lg-10">
<h3>Summary</h3>
<table th:if="${tableData != null}" class=" table table-striped table-bordered table-hover font-sm " data-table data-order="[[ 0, &quot;asc&quot; ]]">
<!-- Scrollable wrapper to prevent overflow -->
<div class="table-responsive">
<table th:if="${tableData != null}"
class="table table-striped table-bordered table-hover font-sm"
data-table
data-order="[[ 0, &quot;asc&quot; ]]"
style="min-width: 1000px;">
<thead>
<tr>
<th colspan="1">SKU / Date</th>
<th class="text-center text-center" th:each="date: ${dateLimits}" >
<span class="d-block " style="width: 100px !important; padding-left: 70px; " th:text="${#temporals.format(date, 'E')}"></span>
<span class="d-block pl-4 " style="width: 150px !important; " ctp:formatdate="${date}" ></span>
<th class="text-center" th:each="date: ${dateLimits}">
<span class="d-block" style="width: 100px !important; padding-left: 70px;"
th:text="${#temporals.format(date, 'E')}"></span>
<span class="d-block pl-4" style="width: 150px !important;"
ctp:formatdate="${date}"></span>
</th>
</tr>
</thead>
<tbody>
<tr th:each="sku : ${tableData.keySet()}">
<!-- SKU Column (first td) -->
<td th:rowspan="${#lists.size(sku)}" th:text="${sku}" class="align-middle" rowspan="3" ></td>
<!-- SKU Column -->
<td th:rowspan="${#lists.size(sku)}"
th:text="${sku}"
class="align-middle"
rowspan="3"></td>
<td th:each="dates: ${dateLimits}" class="p-0">
<table th:each="data : ${tableData.get(sku)}" class="table table-striped table-bordered table-hover font-sm m-0 " >
<table th:each="data : ${tableData.get(sku)}"
class="table table-striped table-bordered table-hover font-sm m-0">
<thead th:if="${data.getKey() == dates.toString()}">
<tr>
<th>ID</th>
@ -58,8 +70,11 @@
</tr>
</tbody>
</table>
</div>
<h4 th:if="${tableData == null}"> No data found </h4>
</div>
</main>
</div>

View File

@ -9,11 +9,9 @@
<header class="row page-header" th:replace="_fragments :: page-header"></header>
<main class="row page-main">
<aside class="col-sm-2" th:replace="/reporting/po-report-sidebar :: sidebar"></aside>
<div class="col-sm">
<div class="col-lg-10 col-sm-10">
<h3>PO's Report</h3>
<div th:replace="_notices :: page-notices"></div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<table class="table table-striped font-sm" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<table class="table table-striped font-sm" data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>PO Number</th>
@ -54,8 +52,8 @@
</tbody>
</table>
<!-- <h4 th:if="${#lists.size(cards) == 0 }">No cards found.</h4>-->
</div>
<!-- <h4 th:if="${#lists.size(cards) == 0 }">No cards found.</h4>-->
</main>
</div>