Fix bugs and add summary report.

pull/1/head
usama.jameel 2024-12-24 12:27:57 +05:00
parent 01f8cd78a6
commit 6cee2380a5
45 changed files with 599 additions and 38 deletions

View File

@ -21,5 +21,10 @@
<option name="name" value="In project repo" />
<option name="url" value="file:///D:\Projects\uind-cut-to-pack\cut-to-pack/libs" />
</remote-repository>
<remote-repository>
<option name="id" value="in-project" />
<option name="name" value="In project repo" />
<option name="url" value="file:///D:\Project\cut-to-pack-service/libs" />
</remote-repository>
</component>
</project>

View File

@ -0,0 +1,14 @@
package com.utopiaindustries.auth;
import org.springframework.security.access.prepost.PreAuthorize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@PreAuthorize( "hasAnyRole('ROLE_REPORTING','ROLE_ADMIN')")
public @interface ReportingRole {
}

View File

@ -38,7 +38,7 @@ public class JobCardController {
@RequestParam( value = "customer" ,required = false ) String customer,
@RequestParam( value = "lot-number", required = false ) String lotNumber,
@RequestParam( value = "purchase-order-id", required = false ) String purchaseOrderId,
@RequestParam( value = "location-site-id", required = false ) String locationSiteId,
@RequestParam( value = "site-id", required = false ) String locationSiteId,
@RequestParam( value = "created-start-date", required = false ) String createdStartDate,
@RequestParam( value = "created-end-date", required = false ) String createdEndDate,
@RequestParam( value = "limit" , required = false) Long limit,

View File

@ -0,0 +1,58 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.CuttingRole;
import com.utopiaindustries.auth.ReportingRole;
import com.utopiaindustries.model.ctp.SummaryInventoryReport;
import com.utopiaindustries.service.SummaryInventoryReportService;
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 java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Controller
@ReportingRole
@RequestMapping( "/reporting" )
public class ReportingController {
private final SummaryInventoryReportService summaryInventoryReportService;
public ReportingController(SummaryInventoryReportService summaryInventoryReportService2) {
this.summaryInventoryReportService = summaryInventoryReportService2;
}
@GetMapping( "/summary")
public String showMasterBundles(@RequestParam(value = "item-id", required = false ) String itemId,
@RequestParam(value = "sku" , required = false) String sku,
@RequestParam(value = "start-date", required = false) String startDate,
@RequestParam(value = "end-date", required = false) String endDate,
Model model ){
Map<String, Map<String, List<SummaryInventoryReport>>> getDataByFilteration = summaryInventoryReportService.findByFilter(itemId,sku,startDate,endDate);
LocalDate startDate1 = StringUtils.isNullOrEmpty(startDate) ? LocalDate.now().minusDays(7) : LocalDate.parse(startDate);
LocalDate endDate1 = StringUtils.isNullOrEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
ArrayList<LocalDate> arrayList = generateDateList(startDate1,endDate1);
model.addAttribute("dateLimits", arrayList);
model.addAttribute("tableData", getDataByFilteration);
if(StringUtils.isNullOrEmpty( startDate) || StringUtils.isNullOrEmpty( endDate )){
return "redirect:/reporting/summary?item-id=&sku=&start-date="+startDate1.toString()+"&end-date="+endDate1;
}
return "/reporting/inventory-summary";
}
private ArrayList<LocalDate> generateDateList(LocalDate start, LocalDate end) {
ArrayList<LocalDate> localDates = new ArrayList<>();
while (start.isBefore(end)) {
localDates.add(start);
start = start.plusDays(1);
}
return localDates;
}
}

View File

@ -0,0 +1,45 @@
package com.utopiaindustries.dao.ctp;
import com.utopiaindustries.model.ctp.SummaryInventoryReport;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class SummaryInventoryReportDao {
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final String TABLE_NAME = "cut_to_pack.inventory_transaction_leg ";
String SELECT_QUERY = "SELECT item_id, account_id, parent_document_id, DATE(transaction_leg_datetime) AS transaction_date, "
+ "sku, parent_document_type, parent_document_piece_type, "
+ "SUM(CASE WHEN type = 'IN' THEN 1 ELSE 0 END) AS total_in, "
+ "SUM(CASE WHEN type = 'OUT' THEN 1 ELSE 0 END) AS total_out "
+ "FROM " + TABLE_NAME + " "
+ "WHERE "
+ "(:sku IS NULL OR sku = :sku) "
+ "AND (:item_id IS NULL OR item_id = :item_id) "
+ "OR (:start_date IS NULL OR :end_date IS NULL OR transaction_leg_datetime BETWEEN :start_date AND :end_date) "
+ "GROUP BY DATE(transaction_leg_datetime), sku, parent_document_type, parent_document_piece_type "
+ "ORDER BY transaction_date, sku;";
public SummaryInventoryReportDao(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
//find by filter for reporting
public List<SummaryInventoryReport> findByFilter(Integer itemId, String sku, String startDate, String endDate) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("sku", sku);
params.addValue("item_id", itemId);
params.addValue("start_date", startDate);
params.addValue("end_date", endDate);
// Query the database and map the result
List<SummaryInventoryReport> results = namedParameterJdbcTemplate.query(SELECT_QUERY, params, new SummaryInventoryReportRowMapper());
return results.isEmpty() ? null : results;
}
}

View File

@ -0,0 +1,23 @@
package com.utopiaindustries.dao.ctp;
import com.utopiaindustries.model.ctp.SummaryInventoryReport;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SummaryInventoryReportRowMapper implements RowMapper<SummaryInventoryReport> {
public SummaryInventoryReport mapRow(ResultSet rs, int rowNum) throws SQLException {
SummaryInventoryReport summaryInventoryReport = new SummaryInventoryReport();
summaryInventoryReport.setItemId(rs.getInt("item_id"));
summaryInventoryReport.setSku(rs.getString("sku"));
summaryInventoryReport.setParentDocumentId(rs.getString("parent_document_id"));
summaryInventoryReport.setAccountId(rs.getString("account_id"));
summaryInventoryReport.setDate(rs.getString("transaction_date"));
summaryInventoryReport.setTotalIn(rs.getLong("total_in"));
summaryInventoryReport.setTotalOut(rs.getLong("total_out"));
summaryInventoryReport.setParentDocumentType(rs.getString("parent_document_type"));
summaryInventoryReport.setParentDocumentPieceType(rs.getString("parent_document_piece_type"));
return summaryInventoryReport;
}
}

View File

@ -8,5 +8,6 @@ public enum Roles {
ROLE_STITCHING,
ROLE_QUALITY_CONTROL,
ROLE_FINISHING,
ROLE_PACKAGING
ROLE_PACKAGING,
ROLE_REPORTING
}

View File

@ -0,0 +1,94 @@
package com.utopiaindustries.model.ctp;
public class SummaryInventoryReport {
private int id;
private int itemId;
private String sku;
private String Date;
private long totalIn;
private long totalOut;
private String parentDocumentType;
private String parentDocumentId;
private String accountId;
private String parentDocumentPieceType;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getItemId() {
return itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
public String getSku() {
return sku;
}
public void setSku(String sku) {
this.sku = sku;
}
public long getTotalIn() {
return totalIn;
}
public void setTotalIn(long totalIn) {
this.totalIn = totalIn;
}
public String getDate() {
return Date;
}
public void setDate(String date) {
Date = date;
}
public long getTotalOut() {
return totalOut;
}
public void setTotalOut(long totalOut) {
this.totalOut = totalOut;
}
public String getParentDocumentType() {
return parentDocumentType;
}
public void setParentDocumentType(String parentDocumentType) {
this.parentDocumentType = parentDocumentType;
}
public String getParentDocumentPieceType() {
return parentDocumentPieceType;
}
public void setParentDocumentPieceType(String parentDocumentPieceType) {
this.parentDocumentPieceType = parentDocumentPieceType;
}
public String getParentDocumentId() {
return parentDocumentId;
}
public void setParentDocumentId(String parentDocumentId) {
this.parentDocumentId = parentDocumentId;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
}

View File

@ -0,0 +1,72 @@
package com.utopiaindustries.querybuilder.ctp;
import com.utopiaindustries.querybuilder.QueryBuilder;
import com.utopiaindustries.util.CTPDateTimeFormat;
import com.utopiaindustries.util.StringUtils;
import java.time.LocalDate;
import java.util.List;
public class SummaryInventoryReportQueryBuilder {
private final static String TABLE_NAME = " cut_to_pack.inventory_transaction_leg ";
public static String buildQuery(String itemId,
String sku,
String startDate,
String endDate) {
// format date
String formattedDate;
String formattedEndDate;
String startDate1 = "";
String endDate1 = "";
String itemId1 = "";
String sku1 = "";
if (!StringUtils.isNullOrEmpty(startDate)) {
formattedDate = CTPDateTimeFormat.getMySQLFormattedDateString(startDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
formattedEndDate = CTPDateTimeFormat.getMySQLFormattedDateString(endDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
startDate1 = String.format("'%s 00:00:01'", formattedDate);
if (!StringUtils.isNullOrEmpty(endDate)) {
endDate1 = String.format("'%s 23:59:59'", formattedEndDate);
} else {
endDate1 = String.format("'%s 23:59:59'", LocalDate.now());
}
}
if (!StringUtils.isNullOrEmpty(itemId)) {
itemId1 = itemId;
}
if (!StringUtils.isNullOrEmpty(sku)) {
sku1 = sku;
}
QueryBuilder qb = new QueryBuilder()
.setTable(TABLE_NAME)
.setColumns("item_id, DATE(transaction_leg_datetime) AS transaction_date, sku, parent_document_type, parent_document_piece_type, "
+ "SUM(CASE WHEN type = 'IN' THEN 1 ELSE 0 END) AS total_in, "
+ "SUM(CASE WHEN type = 'OUT' THEN 1 ELSE 0 END) AS total_out")
.where()
.bracketOpen()
.bracketOpen()
.columnEquals("sku", sku1)
.or()
.columnIsNull("sku")
.bracketClose()
.or()
.bracketOpen()
.columnEquals("item_id",itemId)
.or()
.columnIsNull("item_id")
.bracketClose()
.bracketClose()
.and()
.columnBetween("transaction_leg_date",startDate,endDate)
.groupBy("DATE(transaction_leg_datetime), sku, parent_document_type, parent_document_piece_type")
.orderBy("transaction_date,", "sku");
return qb.build();
}
}

View File

@ -0,0 +1,62 @@
package com.utopiaindustries.service;
import com.utopiaindustries.dao.ctp.SummaryInventoryReportDao;
import com.utopiaindustries.model.ctp.SummaryInventoryReport;
import com.utopiaindustries.util.CTPDateTimeFormat;
import com.utopiaindustries.util.StringUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.*;
@Service
public class SummaryInventoryReportService {
private final SummaryInventoryReportDao summaryInventoryReportDao;
public SummaryInventoryReportService(SummaryInventoryReportDao summaryInventoryReportDao) {
this.summaryInventoryReportDao = summaryInventoryReportDao;
}
public Map<String, Map<String, List<SummaryInventoryReport>>> findByFilter(String itemId, String sku, String startDate, String endDate){
String formattedDate;
String formattedEndDate;
String startDate1 = null;
String endDate1 = null;
Integer itemId1 = null;
String sku1 = null;
if (!StringUtils.isNullOrEmpty(startDate)) {
formattedDate = CTPDateTimeFormat.getMySQLFormattedDateString(startDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
formattedEndDate = CTPDateTimeFormat.getMySQLFormattedDateString(endDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
startDate1 = String.format("'%s 00:00:01'", formattedDate);
if (!StringUtils.isNullOrEmpty(endDate)) {
endDate1 = String.format("'%s 00:00:01'", formattedEndDate);
} else {
endDate1 = String.format("'%s 23:59:59'", LocalDate.now());
}
}
if (!StringUtils.isNullOrEmpty(itemId)) {
itemId1 = Integer.valueOf(itemId);
}
if (!StringUtils.isNullOrEmpty(sku)) {
sku1 = sku;
}
List<SummaryInventoryReport> summaries = summaryInventoryReportDao.findByFilter(itemId1, sku1, startDate1, endDate1);
Map<String, Map<String, List<SummaryInventoryReport>>> tableData = new HashMap<>();
if(summaries == null) {
tableData = null;
}else {
for (SummaryInventoryReport summary : summaries) {
tableData
.computeIfAbsent(summary.getSku(), k -> new HashMap<>()) // SKU as key
.computeIfAbsent(summary.getDate(), d -> new ArrayList<>()) // Date as key
.add(summary);
}
}
return tableData;
}
}

View File

@ -0,0 +1,64 @@
(function( $ ) {
let $btnPreviousWeek = $( '[data-prev-week]' ),
$btnNextWeek = $( '[data-next-week]' ),
$btnResyncWeek = $( '[data-sync-this-week]' ),
$inputDateOfWeek = $( '[data-date-of-week]' );
let currentURL = new URL( window.location.href.split('#')[0] );
$( function () {
console.log( currentURL.href );
});
$inputDateOfWeek.on( 'change', function () {
let $this = $(this);
currentURL.searchParams.delete('date-of-week');
currentURL.searchParams.append( 'date-of-week' , $this.val());
window.location.href = currentURL.href;
} );
$btnPreviousWeek.on( 'click', function () {
let date = new Date( Date.parse( $inputDateOfWeek.val() ) );
let prevWeekDate = new Date( date.setDate( date.getDate() - 7 ) );
let prevWeekDateString = window.uind.utils.getFormattedDateAsISO8601( prevWeekDate );
currentURL.searchParams.delete('date-of-week');
currentURL.searchParams.append( 'date-of-week' , prevWeekDateString );
window.location.href = currentURL.href;
} );
$btnNextWeek.on( 'click', function () {
let date = new Date( Date.parse( $inputDateOfWeek.val() ) );
let nextWeekDate = new Date( date.setDate( date.getDate() + 7 ) );
let nextWeekDateString = window.uind.utils.getFormattedDateAsISO8601( nextWeekDate );
currentURL.searchParams.delete('date-of-week');
currentURL.searchParams.append( 'date-of-week' , nextWeekDateString );
window.location.href = currentURL.href;
} );
$btnResyncWeek.on( 'click', function () {
let date = new Date( Date.parse( $inputDateOfWeek.val() ) );
console.log( date.getDate() );
console.log( date.getDay() );
let startDate = new Date( date.setDate( date.getDate() - date.getDay() + 1 ) );
console.log( startDate );
let endDate = new Date( date.setDate( startDate.getDate() + 6 ) );
console.log( endDate );
let startDateString = window.uind.utils.getFormattedDateAsISO8601( startDate );
let endDateString = window.uind.utils.getFormattedDateAsISO8601( endDate );
currentURL.searchParams.delete('date-of-week');
console.log( ( currentURL.href + '/sync?from-date=' + startDateString + '&to-date=' + endDateString ).replace( '//sync', '/sync' ) );
window.location.href = ( currentURL.href + '/sync?from-date=' + startDateString + '&to-date=' + endDateString ).replace( '//sync', '/sync' );
} );
}( jQuery ));

View File

@ -53,6 +53,12 @@
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/packaging') ? 'active' : ''}">Packaging</a>
</li>
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_PACKAGING', 'ROLE_ADMIN')">
<a th:href="@{/reporting/summary}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting') ? 'active' : ''}">Reporting</a>
</li>
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN')">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Admin</a>
<div class="dropdown-menu">

View File

@ -43,12 +43,18 @@
<label>Lot Number</label>
<input type="text" class="form-control" name="lot-number" maxlength="100" th:value="${param['lot-number']}">
</div>
<div class="form-group" data-vue-app th:with="id=${param['purchase-order-id']},title=${param['purchase-order-code']}">
<div class="form-group" data-vue-app th:with="id=${param['purchase-order-id']},title=${param['purchase-order-id']}">
<purchase-order-search th:attr="id=${id},title=${title}"
v-bind:id-field-name="'purchase-order-id'"
v-bind:code-field-name="'purchase-order-code'"
></purchase-order-search>
</div>
<div class="form-group" data-vue-app th:with="id=${param['site-id']},title=${param['site-title']}">
<location-site-search th:attr="id=${id},title=${title}"
v-bind:id-field-name="'site-id'"
v-bind:title-field-name="'site-title'"
></location-site-search>
</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']}" >

View File

@ -54,7 +54,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" min="0" th:value="${param['count']}">
</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>

View File

@ -44,8 +44,8 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100"
th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}" min="0" step="1" />
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">
<a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"

View File

@ -36,7 +36,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100"
<input type="number" class="form-control" name="count" min="0" maxlength="100"
th:value="${param['count']}">
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">

View File

@ -23,7 +23,7 @@
<div class="container">
<div class="row">
<div class="col-sm-10">
<table class="table table-bordered font-sm" th:if="${#lists.size(transactions) > 0}">
<table th:if="${#lists.size(transactions) != 0 && #lists != null }" class="table table-bordered font-sm">
<thead>
<tr>
<th>ID</th>

View File

@ -50,8 +50,9 @@
<td th:text="${item.createdBy}"></td>
<td ctp:formatdatetime="${item.createdAt}"></td>
<td>
<span th:if="${not item.isSegregated}" class="badge badge-danger">PENDING</span>
<div th:if="${item.isSegregated}">
<span th:if="${not item.isSegregated && !item.qaStatus.equals('ALTER')}" class="badge badge-danger">PENDING</span>
<span th:if="${not item.isSegregated && item.qaStatus.equals('ALTER')}" class="badge" style="background: yellow">REVERTED</span>
<div th:if="${item.isSegregated && !item.qaStatus.equals('ALTER')}">
<span class="badge badge-APPROVED">DONE</span>
</div>
</td>

View File

@ -17,7 +17,7 @@
<a th:href="@{/inventory-accounts/new}" class="btn btn-primary">Add New</a>
</div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<table class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<table th:if="${#lists.size(accounts) != 0 && #lists != null }" class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>ID</th>

View File

@ -16,7 +16,7 @@
<a th:href="@{/job-cards/new}" class="btn btn-primary">Add New</a>
</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 th:if="${#lists.size(cards) != 0 && #lists != null }" class="table table-striped font-sm" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>Code</th>

View File

@ -50,8 +50,9 @@
<td th:text="${item.createdBy}"></td>
<td ctp:formatdatetime="${item.createdAt}"></td>
<td>
<span th:if="${not item.isSegregated}" class="badge badge-danger">PENDING</span>
<div th:if="${item.isSegregated}">
<span th:if="${not item.isSegregated && !item.qaStatus.equals('ALTER')}" class="badge badge-danger">PENDING</span>
<span th:if="${not item.isSegregated && item.qaStatus.equals('ALTER')}" class="badge" style="background: yellow">REVERTED</span>
<div th:if="${item.isSegregated && !item.qaStatus.equals('ALTER')}">
<span class="badge badge-APPROVED">DONE</span>
</div>
</td>

View File

@ -0,0 +1,38 @@
<!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>Item ID</label>
<input type="text" class="form-control" name="item-id" maxlength="100" th:value="${param['item-id']}">
</div>
<div class="form-group">
<label>SKu</label>
<input type="text" class="form-control" name="sku" maxlength="100" th:value="${param['sku']}">
</div>
<div class="form-group">
<label>Start Date</label>
<input type="date" class="form-control" name="start-date" th:value="${param['start-date']}">
</div>
<div class="form-group">
<label>End Date</label>
<input type="date" class="form-control" name="end-date" th:value="${param['end-date']}">
</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

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml"
xmlns:ctp="http://www.w3.org/1999/xhtml">
<head th:replace="_fragments :: head('Summary')"></head>
<body>
<div class="container-fluid">
<header class="row page-header" th:replace="_fragments :: page-header"></header>
<main class="row page-main">
<aside class="col-sm-2" th:replace="/reporting/inventory-summary-sidebar :: sidebar"></aside>
<div class="col-sm">
<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; ]]">
<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>
</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>
<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 " >
<tbody >
<tr th:each="reportSummary : ${data.getValue()}" rowspan="3" >
<td th:if="${data.getKey() == dates.toString()}" >
<span th:text="${reportSummary.getParentDocumentType()} + ' ' + ${reportSummary.getParentDocumentPieceType()}"></span>
</td>
<td th:if="${data.getKey() == dates.toString()}" class="w-25 text-center" >
<span th:text="${reportSummary.getTotalIn() - reportSummary.getTotalOut()}"></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<h4 th:if="${tableData == null}"> No data found </h4>
</div>
</main>
</div>
<div th:replace="_fragments :: page-footer-scripts"></div>
<script th:src="@{/js/summary.js}"></script>
</body>
</html>

View File

@ -33,7 +33,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" min="0" th:value="${param['count']}">
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">

View File

@ -18,7 +18,8 @@
<div class="col-sm-3 p-0">
<master-bundle-search
v-bind:id-field-name="'master-id'"
v-on:master-bundle-select="OnSelect">
v-on:master-bundle-select="OnSelect"
v-bind:required="true">
</master-bundle-search>
</div>
<div class="col-sm-3">

View File

@ -19,7 +19,7 @@
<div th:replace="_fragments :: table-loading-skeleton"></div>
<form th:action="@{/stitching/generate-barcodes}" method="post">
<input hidden="hidden" name="artifactType" value="FinishedItem">
<table class="table table-striped table-bordered" data-table
<table th:if="${#lists.size(items) != 0 && #lists != null }" class="table table-striped table-bordered" data-table
data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>

View File

@ -51,8 +51,8 @@
<th>Production</th>
</tr>
<tbody>
<tr v-for="(item,index) in items">
<td>
<tr v-if="(item.actualProduction !== item.totalProduction)" v-for="(item,index) in items">
<td >
<div class="form-group form-check mb-0">
<input class="form-check-input" type="checkbox" v-bind:name="'items[' + index + '].isSelected'" v-model="item.isSelected">
<label th:for="*{id}" class="form-check-label"></label>

View File

@ -17,7 +17,7 @@
<a th:href="@{/users/new}" class="btn btn-primary">Add New</a>
</div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<table class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<table th:if="${#lists.size(users) != 0 && #lists != null }" class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>User</th>

View File

@ -53,6 +53,12 @@
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/packaging') ? 'active' : ''}">Packaging</a>
</li>
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_PACKAGING', 'ROLE_ADMIN')">
<a th:href="@{/reporting/summary}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting') ? 'active' : ''}">Reporting</a>
</li>
<li class="nav-item dropdown" sec:authorize="hasRole('ROLE_ADMIN')">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Admin</a>
<div class="dropdown-menu">

View File

@ -43,12 +43,18 @@
<label>Lot Number</label>
<input type="text" class="form-control" name="lot-number" maxlength="100" th:value="${param['lot-number']}">
</div>
<div class="form-group" data-vue-app th:with="id=${param['purchase-order-id']},title=${param['purchase-order-code']}">
<div class="form-group" data-vue-app th:with="id=${param['purchase-order-id']},title=${param['purchase-order-id']}">
<purchase-order-search th:attr="id=${id},title=${title}"
v-bind:id-field-name="'purchase-order-id'"
v-bind:code-field-name="'purchase-order-code'"
></purchase-order-search>
</div>
<div class="form-group" data-vue-app th:with="id=${param['site-id']},title=${param['site-title']}">
<location-site-search th:attr="id=${id},title=${title}"
v-bind:id-field-name="'site-id'"
v-bind:title-field-name="'site-title'"
></location-site-search>
</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']}" >

View File

@ -54,7 +54,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" min="0" th:value="${param['count']}">
</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>

View File

@ -44,8 +44,8 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100"
th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}" min="0" step="1" />
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">
<a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"

View File

@ -36,7 +36,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100"
<input type="number" class="form-control" name="count" min="0" maxlength="100"
th:value="${param['count']}">
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">

View File

@ -23,7 +23,7 @@
<div class="container">
<div class="row">
<div class="col-sm-10">
<table class="table table-bordered font-sm" th:if="${#lists.size(transactions) > 0}">
<table th:if="${#lists.size(transactions) != 0 && #lists != null }" class="table table-bordered font-sm">
<thead>
<tr>
<th>ID</th>

View File

@ -50,8 +50,9 @@
<td th:text="${item.createdBy}"></td>
<td ctp:formatdatetime="${item.createdAt}"></td>
<td>
<span th:if="${not item.isSegregated}" class="badge badge-danger">PENDING</span>
<div th:if="${item.isSegregated}">
<span th:if="${not item.isSegregated && !item.qaStatus.equals('ALTER')}" class="badge badge-danger">PENDING</span>
<span th:if="${not item.isSegregated && item.qaStatus.equals('ALTER')}" class="badge" style="background: yellow">REVERTED</span>
<div th:if="${item.isSegregated && !item.qaStatus.equals('ALTER')}">
<span class="badge badge-APPROVED">DONE</span>
</div>
</td>

View File

@ -17,7 +17,7 @@
<a th:href="@{/inventory-accounts/new}" class="btn btn-primary">Add New</a>
</div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<table class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<table th:if="${#lists.size(accounts) != 0 && #lists != null }" class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>ID</th>

View File

@ -16,7 +16,7 @@
<a th:href="@{/job-cards/new}" class="btn btn-primary">Add New</a>
</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 th:if="${#lists.size(cards) != 0 && #lists != null }" class="table table-striped font-sm" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>Code</th>

View File

@ -50,8 +50,9 @@
<td th:text="${item.createdBy}"></td>
<td ctp:formatdatetime="${item.createdAt}"></td>
<td>
<span th:if="${not item.isSegregated}" class="badge badge-danger">PENDING</span>
<div th:if="${item.isSegregated}">
<span th:if="${not item.isSegregated && !item.qaStatus.equals('ALTER')}" class="badge badge-danger">PENDING</span>
<span th:if="${not item.isSegregated && item.qaStatus.equals('ALTER')}" class="badge" style="background: yellow">REVERTED</span>
<div th:if="${item.isSegregated && !item.qaStatus.equals('ALTER')}">
<span class="badge badge-APPROVED">DONE</span>
</div>
</td>

View File

@ -33,7 +33,7 @@
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="count" maxlength="100" th:value="${param['count']}">
<input type="number" class="form-control" name="count" maxlength="100" min="0" th:value="${param['count']}">
</div>
<input type="submit" class="btn btn-secondary btn-block" value="Search">

View File

@ -18,7 +18,8 @@
<div class="col-sm-3 p-0">
<master-bundle-search
v-bind:id-field-name="'master-id'"
v-on:master-bundle-select="OnSelect">
v-on:master-bundle-select="OnSelect"
v-bind:required="true">
</master-bundle-search>
</div>
<div class="col-sm-3">

View File

@ -19,7 +19,7 @@
<div th:replace="_fragments :: table-loading-skeleton"></div>
<form th:action="@{/stitching/generate-barcodes}" method="post">
<input hidden="hidden" name="artifactType" value="FinishedItem">
<table class="table table-striped table-bordered" data-table
<table th:if="${#lists.size(items) != 0 && #lists != null }" class="table table-striped table-bordered" data-table
data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>

View File

@ -51,8 +51,8 @@
<th>Production</th>
</tr>
<tbody>
<tr v-for="(item,index) in items">
<td>
<tr v-if="(item.actualProduction !== item.totalProduction)" v-for="(item,index) in items">
<td >
<div class="form-group form-check mb-0">
<input class="form-check-input" type="checkbox" v-bind:name="'items[' + index + '].isSelected'" v-model="item.isSelected">
<label th:for="*{id}" class="form-check-label"></label>

View File

@ -17,7 +17,7 @@
<a th:href="@{/users/new}" class="btn btn-primary">Add New</a>
</div>
<div th:replace="_fragments :: table-loading-skeleton"></div>
<table class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<table th:if="${#lists.size(users) != 0 && #lists != null }" class="table table-striped table-bordered" data-table data-order="[[ 0, &quot;asc&quot; ]]">
<thead>
<tr>
<th>User</th>