Merge pull request 'add stitching report dashboard' (#19) from add-stitching-dashboard into main

Reviewed-on: #19
main
saif.haq 2025-04-24 05:23:36 +00:00
commit 6ac6a42a60
11 changed files with 529 additions and 108 deletions

View File

@ -95,6 +95,36 @@ public class ReportingController {
return "/reporting/cutting-report"; return "/reporting/cutting-report";
} }
@GetMapping( value = "/stitching-report" )
public String stitchingReport(@RequestParam(value = "job-card-id", required = false ) String jobCardId, @RequestParam(value = "accountId" , required = false) String accountId, @RequestParam(value = "start-date", required = false) String startDate, @RequestParam(value = "end-date", required = false) String endDate, Model model ){
LocalDate startDate1 = StringUtils.isNullOrEmpty(startDate) ? LocalDate.now().minusDays(31) : LocalDate.parse(startDate);
LocalDate endDate1 = StringUtils.isNullOrEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
model.addAttribute("startDate", startDate1);
model.addAttribute("endDate", endDate1);
model.addAttribute("accounts" , inventoryAccountService.findInventoryAccounts( 2L ) );
model.addAttribute("stitching",reportingService.getStitchingDetails(jobCardId, accountId, startDate1.toString(), endDate1.toString()));
return "/reporting/stitching-report";
}
@GetMapping( "/inventory-transactions" )
public String getInventoryTransactionsByAccount( @RequestParam( value = "account-id", required = false) String accountId,
@RequestParam( value = "jobCard-id", required = false) String jobCardId,
@RequestParam( value = "sku", required = false) String sku,
@RequestParam( value = "startDate", required = false) String startDate,
@RequestParam( value = "endDate", required = false) String endDate,
Model model ){
LocalDate startDate1 = StringUtils.isNullOrEmpty(startDate) ? LocalDate.now().minusDays(31) : LocalDate.parse(startDate);
LocalDate endDate1 = StringUtils.isNullOrEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
model.addAttribute("startDate", startDate1);
model.addAttribute("endDate", endDate1);
model.addAttribute("transactions", reportingService.stitchingItemsTransactions( jobCardId, accountId, sku, startDate1.toString(), endDate1.toString() ));
return "/reporting/accounts-transaction-table";
}
private ArrayList<LocalDate> generateDateList(LocalDate start, LocalDate end) { private ArrayList<LocalDate> generateDateList(LocalDate start, LocalDate end) {
ArrayList<LocalDate> localDates = new ArrayList<>(); ArrayList<LocalDate> localDates = new ArrayList<>();
while (start.isBefore(end)) { while (start.isBefore(end)) {

View File

@ -4,7 +4,7 @@ public class CuttingJobCardItemWrapper {
private long jobCardId; private long jobCardId;
private String poName; private String poName;
private String sku; private String sku;
private Long totalCutting; private Long total;
private String width; private String width;
private String length; private String length;
private String gsm; private String gsm;
@ -13,8 +13,8 @@ public class CuttingJobCardItemWrapper {
private String articleName; private String articleName;
private boolean isComplete; private boolean isComplete;
private String jobCardCode; private String jobCardCode;
private String cuttingOperatorName; private String operatorName;
private long cuttingAccountId; private long accountId;
public long getJobCardId() { public long getJobCardId() {
return jobCardId; return jobCardId;
@ -40,14 +40,6 @@ public class CuttingJobCardItemWrapper {
this.sku = sku; this.sku = sku;
} }
public Long getTotalCutting() {
return totalCutting;
}
public void setTotalCutting(Long totalCutting) {
this.totalCutting = totalCutting;
}
public String getWidth() { public String getWidth() {
return width; return width;
} }
@ -104,13 +96,6 @@ public class CuttingJobCardItemWrapper {
this.jobCardCode = jobCardCode; this.jobCardCode = jobCardCode;
} }
public long getCuttingAccountId() {
return cuttingAccountId;
}
public void setCuttingAccountId(long cuttingAccountId) {
this.cuttingAccountId = cuttingAccountId;
}
public String getLength() { public String getLength() {
return length; return length;
@ -120,31 +105,47 @@ public class CuttingJobCardItemWrapper {
this.length = length; this.length = length;
} }
public String getCuttingOperatorName() { public String getOperatorName() {
return cuttingOperatorName; return operatorName;
} }
public void setCuttingOperatorName(String cuttingOperatorName) { public void setOperatorName(String operatorName) {
this.cuttingOperatorName = cuttingOperatorName; this.operatorName = operatorName;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
} }
@Override @Override
public String toString() { public String toString() {
return "CuttingJobCardItemWrapper{" + return "CuttingJobCardItemWrapper{" +
"cuttingAccountId=" + cuttingAccountId + "jobCardId=" + jobCardId +
", cuttingOperatorName='" + cuttingOperatorName + '\'' +
", jobCardCode='" + jobCardCode + '\'' +
", isComplete=" + isComplete +
", articleName='" + articleName + '\'' +
", ply='" + ply + '\'' +
", wtPly='" + wtPly + '\'' +
", gsm='" + gsm + '\'' +
", length='" + length + '\'' +
", width='" + width + '\'' +
", totalCutting=" + totalCutting +
", sku='" + sku + '\'' +
", poName='" + poName + '\'' + ", poName='" + poName + '\'' +
", jobCardId=" + jobCardId + ", sku='" + sku + '\'' +
", total=" + total +
", width='" + width + '\'' +
", length='" + length + '\'' +
", gsm='" + gsm + '\'' +
", wtPly='" + wtPly + '\'' +
", ply='" + ply + '\'' +
", articleName='" + articleName + '\'' +
", isComplete=" + isComplete +
", jobCardCode='" + jobCardCode + '\'' +
", operatorName='" + operatorName + '\'' +
", accountId=" + accountId +
'}'; '}';
} }
} }

View File

@ -71,8 +71,11 @@ public class SummaryInventoryReportQueryBuilder {
public static String cuttingQueryBuild(long jobCardId, public static String cuttingQueryBuild(long jobCardId,
List<Long> account, List<Long> account,
String sku,
String startDate, String startDate,
String endDate,String type) { String endDate,
String type,
String parentDocumentType) {
QueryBuilder qb = new QueryBuilder() QueryBuilder qb = new QueryBuilder()
.setTable(TABLE_NAME) .setTable(TABLE_NAME)
@ -84,11 +87,17 @@ public class SummaryInventoryReportQueryBuilder {
.and() .and()
.columnEqualToOrLessThan("transaction_leg_datetime",endDate) .columnEqualToOrLessThan("transaction_leg_datetime",endDate)
.and() .and()
.columnEquals("type",type); .columnEquals("type",type)
.and()
.columnEquals("parent_document_type",parentDocumentType);
if (jobCardId != 0){ if (jobCardId != 0){
qb.and() qb.and()
.columnEquals("job_card_id", jobCardId ); .columnEquals("job_card_id", jobCardId );
} }
if (!StringUtils.isNullOrEmpty(sku)){
qb.and()
.columnEquals("sku", sku );
}
return qb.build(); return qb.build();
} }
} }

View File

@ -351,13 +351,18 @@ public class BarcodeService {
PdfFont font = PdfFontFactory.createFont(StandardFonts.COURIER_OBLIQUE); PdfFont font = PdfFontFactory.createFont(StandardFonts.COURIER_OBLIQUE);
String id = String.valueOf(artifact.getId()); String id = String.valueOf(artifact.getId());
float textSize = stickerSize.getTextSize() + 8;
float charWidth = textSize * 0.6f;
float idWidth = id.length() * charWidth;
float xCentered = (labelWidth / 2f) - (idWidth / 2f);
document.add(new Paragraph(id) document.add(new Paragraph(id)
.setFont(font) .setFont(font)
.setBold() .setBold()
.setFontColor(ColorConstants.BLACK) .setFontColor(ColorConstants.BLACK)
.setFontSize(stickerSize.getTextSize() + 8) .setFontSize(textSize)
.setTextAlignment(TextAlignment.LEFT) .setFixedPosition(xCentered, textY + 13, 100));
.setFixedPosition(textX - 25, textY + 13, 100));
float dottedLine = textY - 65; float dottedLine = textY - 65;
for(int i= 0 ;i<16;i++){ for(int i= 0 ;i<16;i++){

View File

@ -618,7 +618,7 @@ public class ReportingService {
inventoryAccountIds = List.of(Long.parseLong(cuttingTableId)); inventoryAccountIds = List.of(Long.parseLong(cuttingTableId));
} }
String query = SummaryInventoryReportQueryBuilder.cuttingQueryBuild(jobCardIdTemp, inventoryAccountIds, startDate1, endDate1, "IN"); String query = SummaryInventoryReportQueryBuilder.cuttingQueryBuild(jobCardIdTemp, inventoryAccountIds, null, startDate1, endDate1, "IN","BUNDLE");
List<InventoryTransactionLeg> inventoryTransactionLegs = inventoryTransactionLegDAO.findByQuery(query); List<InventoryTransactionLeg> inventoryTransactionLegs = inventoryTransactionLegDAO.findByQuery(query);
Map<String, Integer> dateWiseProduction = new TreeMap<>(); Map<String, Integer> dateWiseProduction = new TreeMap<>();
@ -670,15 +670,15 @@ public class ReportingService {
wrapper.setGsm(item.getGsm()); wrapper.setGsm(item.getGsm());
wrapper.setPly(item.getPly()); wrapper.setPly(item.getPly());
wrapper.setSku(item.getSku()); wrapper.setSku(item.getSku());
wrapper.setTotalCutting(item.getActualProduction().longValue()); wrapper.setTotal(item.getActualProduction().longValue());
wrapper.setWidth(item.getWidth()); wrapper.setWidth(item.getWidth());
wrapper.setWtPly(item.getWtPly()); wrapper.setWtPly(item.getWtPly());
wrapper.setComplete(item.isComplete()); wrapper.setComplete(item.isComplete());
wrapper.setPoName(jobCard.getPurchaseOrderId()); wrapper.setPoName(jobCard.getPurchaseOrderId());
wrapper.setCuttingOperatorName(bundle.getCreatedBy()); wrapper.setOperatorName(bundle.getCreatedBy());
wrapper.setJobCardId(item.getJobCardId()); wrapper.setJobCardId(item.getJobCardId());
wrapper.setLength(item.getLength()); wrapper.setLength(item.getLength());
wrapper.setCuttingAccountId(accountId); wrapper.setAccountId(accountId);
return wrapper; return wrapper;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@ -691,6 +691,129 @@ public class ReportingService {
return cuttingDetails; return cuttingDetails;
} }
public Map<String, Object> getStitchingDetails(String jobCardId, String stitchingLine, String startDate, String endDate) {
Map<String, Object> stitchingDetails = new HashMap<>();
long jobCardIdTemp = 0L;
String startDate1 = null;
String endDate1 = null;
if (!StringUtils.isNullOrEmpty(startDate)) {
String formattedStart = CTPDateTimeFormat.getMySQLFormattedDateString(startDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
String formattedEnd = !StringUtils.isNullOrEmpty(endDate)
? CTPDateTimeFormat.getMySQLFormattedDateString(endDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT)
: LocalDate.now().toString();
startDate1 = String.format("'%s 00:00:01'", formattedStart);
endDate1 = String.format("'%s 23:59:59'", formattedEnd);
}
List<InventoryAccount> inventoryAccounts = inventoryAccountDAO.findByParentEntityTypeAndParentId("PROCESS", 2L);
List<Long> inventoryAccountIds = inventoryAccounts.stream().map(InventoryAccount::getId).collect(Collectors.toList());
if (!StringUtils.isNullOrEmpty(jobCardId)) {
jobCardIdTemp = Long.parseLong(jobCardId);
} else if (!StringUtils.isNullOrEmpty(stitchingLine)) {
inventoryAccountIds = List.of(Long.parseLong(stitchingLine));
}
String query = SummaryInventoryReportQueryBuilder.cuttingQueryBuild(jobCardIdTemp, inventoryAccountIds,null, startDate1, endDate1, "IN","STITCHING_OFFLINE");
List<InventoryTransactionLeg> inventoryTransactionLegs = inventoryTransactionLegDAO.findByQuery(query);
Map<String, Integer> dateWiseProduction = new TreeMap<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
Map<LocalDate, List<Long>> dateWiseJobCardIds = inventoryTransactionLegs.stream()
.filter(e -> e.getTransactionLegDateTime() != null && e.getJobCardId() != 0)
.collect(Collectors.groupingBy(
e -> e.getTransactionLegDateTime().toLocalDate(),
Collectors.mapping(InventoryTransactionLeg::getJobCardId, Collectors.toList())
));
for (Map.Entry<LocalDate, List<Long>> entry : dateWiseJobCardIds.entrySet()) {
LocalDate date = entry.getKey();
List<Long> jobCardIds = entry.getValue();
if (!jobCardIds.isEmpty()) {
int totalProduction = inventoryTransactionLegs.stream()
.filter(item -> jobCardIds.contains(item.getJobCardId()) &&
"STITCHING_OFFLINE".equals(item.getParentDocumentType()) && item.getTransactionLegDateTime().toLocalDate().equals(date))
.mapToInt(item -> item.getQuantity().intValue())
.sum();
dateWiseProduction.put(date.format(formatter), totalProduction);
}
}
List<Long> distinctJobCardIds = inventoryTransactionLegs.stream()
.map(InventoryTransactionLeg::getJobCardId)
.filter(id -> id != 0)
.distinct()
.collect(Collectors.toList());
Map<Long, List<CuttingJobCardItemWrapper>> jobCardItemsStitchingDetailsMap = new HashMap<>();
Map<String, Integer> totalStitchingBasedOnAccountID = new HashMap<>();
for (long jobCardIdEntry : distinctJobCardIds) {
Long accountId = inventoryTransactionLegs.stream()
.filter(e -> e.getJobCardId() == jobCardIdEntry)
.map(e -> e.getAccountId().longValue())
.findFirst()
.orElse(0L);
JobCard jobCard = jobCardDAO.find(jobCardIdEntry);
List<StitchingOfflineItem> stitchingOfflineItem = stitchingOfflineItemDAO.findByJobCardId(jobCardIdEntry);
List<JobCardItem> jobCardItems = jobCardItemDAO.findByCardId(jobCardIdEntry);
List<CuttingJobCardItemWrapper> wrappers = jobCardItems.stream().map(item -> {
CuttingJobCardItemWrapper wrapper = new CuttingJobCardItemWrapper();
wrapper.setArticleName(jobCard.getArticleName());
wrapper.setJobCardId(jobCard.getId());
wrapper.setJobCardCode(jobCard.getCode());
wrapper.setSku(item.getSku());
wrapper.setPoName(jobCard.getPurchaseOrderId());
wrapper.setJobCardId(item.getJobCardId());
wrapper.setOperatorName(stitchingOfflineItem.get(0).getCreatedBy());
wrapper.setAccountId(accountId);
return wrapper;
}).collect(Collectors.toList());
totalStitchingBasedOnAccountID.put(jobCard.getId()+stitchingOfflineItem.get(0).getSku(), stitchingOfflineItem.size());
jobCardItemsStitchingDetailsMap.computeIfAbsent(accountId, k -> new ArrayList<>()).addAll(wrappers);
}
stitchingDetails.put("totalStitchingBasedOnAccountID", totalStitchingBasedOnAccountID);
stitchingDetails.put("jobCardItemsStitchingDetailsMap", jobCardItemsStitchingDetailsMap);
stitchingDetails.put("Date Wise Stitching", dateWiseProduction);
stitchingDetails.put("stitchingAccount", inventoryAccounts);
return stitchingDetails;
}
public List<StitchingOfflineItem> stitchingItemsTransactions(String jobCardId, String accountId, String sku, String startDate, String endDate) {
List<Long> accountID = new ArrayList<>();
String startDate1 = null;
String endDate1 = null;
if (!StringUtils.isNullOrEmpty(startDate) && !StringUtils.isNullOrEmpty(accountId) && !StringUtils.isNullOrEmpty(jobCardId)) {
String formattedStart = CTPDateTimeFormat.getMySQLFormattedDateString(startDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT);
String formattedEnd = !StringUtils.isNullOrEmpty(endDate)
? CTPDateTimeFormat.getMySQLFormattedDateString(endDate, CTPDateTimeFormat.HTML5_DATE_INPUT_FORMAT)
: LocalDate.now().toString();
startDate1 = String.format("'%s 00:00:01'", formattedStart);
endDate1 = String.format("'%s 23:59:59'", formattedEnd);
accountID.add(Long.parseLong(accountId));
}
String query = SummaryInventoryReportQueryBuilder.cuttingQueryBuild(Long.parseLong(jobCardId), accountID, sku, startDate1, endDate1,"IN","STITCHING_OFFLINE");
List<InventoryTransactionLeg> inventoryTransactionLegs = inventoryTransactionLegDAO.findByQuery(query);
List<Long> stitchingItemsList = inventoryTransactionLegs.stream()
.map(InventoryTransactionLeg::getParentDocumentId)
.collect(Collectors.toList());
return stitchingOfflineItemDAO.findByIds(stitchingItemsList);
}
private StringBuilder generateTime(LocalDateTime startDate, LocalDateTime endDate){ private StringBuilder generateTime(LocalDateTime startDate, LocalDateTime endDate){
StringBuilder totalTime = new StringBuilder(); StringBuilder totalTime = new StringBuilder();

View File

@ -137,65 +137,69 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
} }
function createSingleBarChart(divId, height, width, title,Heading, Data, dates, fontSize, maxValue) { function createSingleBarChart(divId, height, width, title,Heading, Data, dates, fontSize, maxValue) {
if (!document.getElementById(divId)) { if (!document.getElementById(divId)) {
return; return;
} }
Highcharts.chart(divId, { Highcharts.chart(divId, {
chart: { chart: {
type: 'column', type: 'column',
height: height, height: height,
width: width, width: width,
}, },
title: { title: {
text: title, text: title,
align: 'center', align: 'center',
verticalAlign: 'top', verticalAlign: 'top',
y: 30, y: 30,
style: { style: {
fontSize: fontSize, fontSize: fontSize,
fontWeight: 'bold', fontWeight: 'bold',
} }
}, },
xAxis: { xAxis: {
categories: dates, categories: dates,
labels: { labels: {
rotation: -45, rotation: -45,
style: { style: {
fontSize: 10-fontSize, fontSize: 10-fontSize,
fontWeight: 'bold' fontWeight: 'bold'
} }
} }
}, },
yAxis: { yAxis: {
min: 0, min: 0,
max: maxValue, max: maxValue,
softMax: maxValue, softMax: maxValue,
softMin: 0, softMin: 0,
startOnTick: true, startOnTick: true,
endOnTick: true, endOnTick: true,
title: { title: {
text: 'Total Progress', text: 'Total Progress',
style: { style: {
fontSize: fontSize, fontSize: fontSize,
fontWeight: 'bold', fontWeight: 'bold',
} }
}, },
labels: { labels: {
format: '{value}%' format: '{value}%'
} }
}, },
legend: {
scrollbar: { itemStyle: {
enabled: true fontSize: 10-fontSize,
}, fontWeight: 'bold'
series: [{ }
name: Heading, },
data: Data scrollbar: {
}] enabled: true
}); },
} series: [{
name: Heading,
data: Data
}]
});
}
initializeGauges(); initializeGauges();
function initializeGauges() { function initializeGauges() {
@ -256,7 +260,7 @@ document.addEventListener("DOMContentLoaded", function () {
createBarChart( divId, height, width, title, aHeading, aData, bHeading, bData, cHeading, cData, dHeading, dData, datesArray, fontSize, maxValue); createBarChart( divId, height, width, title, aHeading, aData, bHeading, bData, cHeading, cData, dHeading, dData, datesArray, fontSize, maxValue);
}); });
const cuttingBarChart = document.querySelectorAll('.cuttingBarChart'); const cuttingBarChart = document.querySelectorAll('.singleBarChart');
cuttingBarChart.forEach(function (div) { cuttingBarChart.forEach(function (div) {
const title = div.getAttribute('data-title'); const title = div.getAttribute('data-title');
const height = div.getAttribute('data-height'); const height = div.getAttribute('data-height');

View File

@ -144,6 +144,10 @@
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting/cutting-report') ? 'active' : ''}"> th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting/cutting-report') ? 'active' : ''}">
<a th:href="@{/reporting/cutting-report}" class="nav-link">Cutting Tables Report</a> <a th:href="@{/reporting/cutting-report}" class="nav-link">Cutting Tables Report</a>
</li> </li>
<li class="nav-item"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting/stitching-report') ? 'active' : ''}">
<a th:href="@{/reporting/stitching-report}" class="nav-link">Stitching Line Report</a>
</li>
<li class="nav-item" <li class="nav-item"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting/summary') ? 'active' : ''}"> th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/reporting/summary') ? 'active' : ''}">
<a th:href="@{/reporting/summary}" class="nav-link">Summary</a> <a th:href="@{/reporting/summary}" class="nav-link">Summary</a>

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
/* Custom CSS for full height and center alignment of span */
.vertical-divider {
display: flex;
justify-content: center; /* Center horizontally */
align-items: center; /* Center vertically */
}
.vertical-divider span {
display: inline-block;
width: 1px;
background-color: #dee2e6;
height: 100%; /* Take full height of the parent div */
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-12">
<table th:if="${#lists.size(transactions) != 0 && #lists != null }" class="table table-bordered font-sm mb-4" data-account-tables>
<thead>
<tr>
<th>ID</th>
<th>Item ID</th>
<th>SKU</th>
<th>QR Code</th>
<th>Created By</th>
<th>Created At</th>
<th>Bundle Id</th>
<th>QA Status</th>
</tr>
</thead>
<tbody>
<tr th:each="transaction : ${transactions}" th:object="${transaction}">
<td th:text="*{id}"></td>
<td th:text="*{itemId}"></td>
<td th:text="*{sku}"></td>
<td th:text="*{barcode}"></td>
<td th:text="*{createdBy}"></td>
<td th:text="*{createdAt}"></td>
<td th:text="*{bundleId}"></td>
<td>
<span th:if="*{ not isQa}" class="badge badge-danger">NOT PERFORMED</span>
<div th:if="*{isQa}">
<span class="badge badge-APPROVED">PERFORMED</span>
</div>
</td>
</tr>
<!-- More rows as needed -->
</tbody>
</table>
<h5 th:if="${#lists.size(transactions) == 0}" class="mt-2">No Inventory Transactions found.</h5>
</div>
</div>
</div>
<div th:replace="_fragments :: page-footer-scripts"></div>
<script th:inline="javascript">
// Initialize DataTables for each individual table
$('table[data-account-tables]').each(function () {
const $table = $(this);
// Prevent reinitializing if already done
if (!$.fn.DataTable.isDataTable($table)) {
$table.DataTable({
pageLength: 5,
searching: true,
lengthChange: false,
processing: false,
dom: `
<'row'<'col-sm-5'B><'col-sm-7'f>>
<'row'<'col-sm-12't>>
<'row'<'col-sm-5'i><'col-sm-7'p>>`,
buttons: [{
extend: 'excel',
text: '',
className: 'bi bi-file-earmark-spreadsheet btn-sm d-none' // Keep it hidden
}]
});
}
});
(async function () {
const $selectAllCheckBox = $('[data-checkbox-all]');
$selectAllCheckBox.change(function () {
if ($selectAllCheckBox.prop('checked')) {
// When parent checkbox is checked, check all child checkboxes
$('[name="parent-doc-type-ids"]').each(function () {
let $this = $(this);
$this.prop('checked', true);
});
} else {
// When parent checkbox is unchecked, uncheck all child checkboxes
$('[name="parent-doc-type-ids"]').each(function () {
let $this = $(this);
$this.prop('checked', false);
});
}
});
})(jQuery)
</script>
</body>
</html>

View File

@ -22,7 +22,7 @@
<input type="date" class="form-control" name="end-date" th:value="${param['end-date'] ?: endDate}"> <input type="date" class="form-control" name="end-date" th:value="${param['end-date'] ?: endDate}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Cutting Account</label> <label>Select Account</label>
<select class="form-control" name="accountId"> <select class="form-control" name="accountId">
<option value="">Please Select</option> <option value="">Please Select</option>
<option th:each="account : ${accounts}" <option th:each="account : ${accounts}"

View File

@ -15,7 +15,7 @@
<tr> <tr>
<td th:if="${cutting.get('Date Wise Cutting') != null}" style="padding-left: 150px;"> <td th:if="${cutting.get('Date Wise Cutting') != null}" style="padding-left: 150px;">
<div style="border: 2px solid #d5d8dc; padding-top: 10px; border-radius: 10px; height: 560px; width: 80%; overflow-x: auto;"> <div style="border: 2px solid #d5d8dc; padding-top: 10px; border-radius: 10px; height: 560px; width: 80%; overflow-x: auto;">
<div id="cuttingBarChart" class="cuttingBarChart" style="height: 500px; width: 1600px;" <div id="singleBarChart" class="singleBarChart" style="height: 500px; width: 1600px;"
th:data-width="1600" th:data-width="1600"
th:data-height="500" th:data-height="500"
th:data-title="'Days Wise Progress'" th:data-title="'Days Wise Progress'"
@ -57,8 +57,8 @@
<td th:text="${wrap.poName}"></td> <td th:text="${wrap.poName}"></td>
<td th:text="${wrap.sku}"></td> <td th:text="${wrap.sku}"></td>
<td th:text="${wrap.articleName}"></td> <td th:text="${wrap.articleName}"></td>
<td th:text="${wrap.totalCutting}"></td> <td th:text="${wrap.total}"></td>
<td th:text="${wrap.cuttingOperatorName}"></td> <td th:text="${wrap.operatorName}"></td>
<td th:text="${wrap.width}"></td> <td th:text="${wrap.width}"></td>
<td th:text="${wrap.length}"></td> <td th:text="${wrap.length}"></td>
<td th:text="${wrap.gsm}"></td> <td th:text="${wrap.gsm}"></td>

View File

@ -0,0 +1,132 @@
<!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('Stitching Report')"></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/cutting-report-sidebar :: sidebar"></aside>
<div class="col-lg-10">
<div th:if="${stitching.get('Date Wise Stitching') != null}" style="padding-left: 150px;">
<div style="border: 2px solid #d5d8dc; padding-top: 10px; border-radius: 10px; height: 560px; width: 80%; overflow-x: auto;">
<div id="singleBarChart" class="singleBarChart" style="height: 500px; width: 1600px;"
th:data-width="1600"
th:data-height="500"
th:data-title="'Days Wise Progress'"
th:data-dates="${stitching.get('Date Wise Stitching').keySet()}"
th:data-barData="${stitching.get('Date Wise Stitching').values()}"
th:data-barHeading="'Stitching'"
th:data-stitching="''"
th:data-quality="''"
th:data-finishing="''"
th:data-totalProduction="'500'"
th:data-fontSize="30"
></div>
</div>
</div>
<div class="mt-3" th:if="${stitching.get('stitchingAccount') != null && stitching.get('jobCardItemsStitchingDetailsMap').get(stitchingAccount.id) != null}"
th:each="stitchingAccount, index : ${stitching.get('stitchingAccount')}">
<div class="bg-dark text-white py-2 px-3 fs-5 fw-bold text-center mb-2"
th:text="${stitchingAccount.title}"></div>
<table class="table table-striped " data-account-table th:data-account-id="${stitchingAccount.id}">
<thead>
<tr>
<th></th>
<th>Job Card</th>
<th>PO Number</th>
<th>SKU</th>
<th>Article Name</th>
<th>Stitching Operator Name</th>
<th>Total Stitching</th>
</tr>
</thead>
<tbody>
<tr th:each="wrap, index : ${stitching.get('jobCardItemsStitchingDetailsMap').get(stitchingAccount.id)}">
<td data-show-dropdown-transactions
th:data-account-id="${stitchingAccount.id}"
th:data-jobcardid="${wrap.jobCardId}"
th:data-sku="${wrap.sku}"
th:data-start-date="${param['start-date'] ?: startDate}"
th:data-end-date="${param['end-date'] ?: endDate}"
title="Transactions">
<span data-dropdown-icon-transactions class="bi bi-caret-right-fill"></span>
</td>
<td th:text="${wrap.jobCardCode}"></td>
<td th:text="${wrap.poName}"></td>
<td th:text="${wrap.sku}"></td>
<td th:text="${wrap.articleName}"></td>
<td th:text="${wrap.operatorName}"></td>
<td th:text="${stitching.get('totalStitchingBasedOnAccountID').get(wrap.jobCardId+wrap.sku)}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
</div>
<script>
const $body = $('body');
// Initialize DataTables for each individual table
$('table[data-account-table]').each(function () {
$(this).DataTable({
paging: false,
pageLength: 100,
searching: false,
lengthChange: false,
processing: false,
dom: `
<'row'<'col-sm-5'B><'col-sm-7'f>>
<'row'<'col-sm-12't>>
<'row'<'col-sm-5'i><'col-sm-7'p>>`,
buttons: [{
extend: 'excel',
text: '',
className: 'bi bi-file-earmark-spreadsheet btn-sm d-none'
}]
});
});
// Dropdown transactions toggle
$body.on('click', '[data-show-dropdown-transactions]', function (e) {
e.preventDefault();
const $this = $(this);
const $tr = $this.closest('tr');
const $table = $this.closest('table');
const dataTable = $table.DataTable();
const $row = dataTable.row($tr);
const $spanDropdown = $this.find('[data-dropdown-icon-transactions]');
const accountId = $this.data('account-id');
const jobCardId = $this.data('jobcardid');
const sku = $this.data('sku');
const startDate = $this.data('start-date');
const endDate = $this.data('end-date');
$spanDropdown.toggleClass('bi-caret-right-fill bi-caret-down-fill');
if ($row.child.isShown()) {
$row.child.hide();
} else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/reporting/inventory-transactions?account-id=${accountId}&jobCard-id=${jobCardId}&sku=${sku}&startDate=${startDate}&endDate=${endDate}`,
success: function (data) {
$row.child(data).show();
}
});
}
});
</script>
<!-- Load JavaScript file -->
<script th:src="@{/js/charts.js}"></script>
</body>
</html>