Added errors pages

pull/1/head
saif 2024-12-18 09:33:10 +05:00
parent 17b0acb58a
commit 63bca96dc7
78 changed files with 1432 additions and 711 deletions

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_ADMIN')")
public @interface AdminRole {
}

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_CUTTING','ROLE_ADMIN')")
public @interface CuttingRole {
}

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_FINISHING','ROLE_ADMIN')")
public @interface FinishingRole {
}

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_JOB_CARD','ROLE_ADMIN')")
public @interface JobCardRole {
}

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_PACKAGING','ROLE_ADMIN')")
public @interface PackagingRole {
}

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_QUALITY_CONTROL','ROLE_ADMIN')")
public @interface QCRole {
}

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_STITCHING','ROLE_ADMIN')")
public @interface StitchingRole {
}

View File

@ -1,6 +1,8 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.CuttingRole;
import com.utopiaindustries.dao.ctp.BundleWrapper;
import com.utopiaindustries.model.ctp.JobCardWrapper;
import com.utopiaindustries.service.*;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
@ -12,6 +14,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.Arrays;
@Controller
@CuttingRole
@RequestMapping( "/cutting" )
public class CuttingController {
@ -39,8 +42,9 @@ public class CuttingController {
@GetMapping( "/receive-inventory" )
public String receiveInventoryForm( Model model ){
// 1 for cutting accounts
model.addAttribute("accounts" , inventoryAccountService.findInventoryAccounts( 1L ) );
model.addAttribute("accounts" , inventoryAccountService.getAllCuttingAccounts() );
model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() );
model.addAttribute("wrapper", new JobCardWrapper() );
return "/cutting/receive-inventory";
}
@ -63,12 +67,12 @@ public class CuttingController {
}
@PostMapping( "/receive-inventory" )
public String receiveInventoryToCuttingAccount( Model model,
RedirectAttributes redirectAttributes,
@RequestParam( "job-card-id" ) long jobCardId,
@RequestParam( "account-id" ) long accountId ){
public String receiveInventoryToCuttingAccount(Model model,
RedirectAttributes redirectAttributes,
@RequestParam( "job-card-id" ) long jobCardId,
@ModelAttribute JobCardWrapper wrapper ){
try {
inventoryService.receiveJobCardInventory( jobCardId, accountId );
inventoryService.receiveJobCardInventory( jobCardId, wrapper );
redirectAttributes.addFlashAttribute("success", "Inventory Success Received" );
} catch ( Exception ex ){
redirectAttributes.addFlashAttribute("error", ex.getMessage() );
@ -77,18 +81,7 @@ public class CuttingController {
}
@GetMapping( "/inventory-transactions" )
public String getInventoryTransactionsByAccount( @RequestParam( value = "account-id", required = true) long accountId,
Model model ){
model.addAttribute("transactions", inventoryService.findTransactionByAccountId( accountId ));
return "/cutting/inventory-transactions";
}
@GetMapping( "/inventory-summary" )
public String getInventorySummaryByAccount( @RequestParam( value = "account-id", required = true) long accountId, Model model ){
model.addAttribute("summaries", inventoryService.findItemSummaryByAccountId( accountId ));
return "/cutting/inventory-summary";
}
@GetMapping( "/generate-master-barcode" )
public String showMasterBundleForm( Model model ){

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.FinishingRole;
import com.utopiaindustries.dao.ctp.FinishedItemDAO;
import com.utopiaindustries.model.ctp.FinishedItem;
import com.utopiaindustries.model.ctp.FinishedItemWrapper;
@ -15,6 +16,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller
@FinishingRole
@RequestMapping( "/finishing" )
public class FinishingController {

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.AdminRole;
import com.utopiaindustries.model.ctp.InventoryAccount;
import com.utopiaindustries.service.InventoryAccountService;
import org.springframework.stereotype.Controller;
@ -8,6 +9,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
@AdminRole
@RequestMapping( "/inventory-accounts" )
public class InventoryAccountController {

View File

@ -0,0 +1,32 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.service.InventoryService;
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;
@Controller
@RequestMapping
public class InventoryTransactionController {
private final InventoryService inventoryService;
public InventoryTransactionController(InventoryService inventoryService) {
this.inventoryService = inventoryService;
}
@GetMapping( "/inventory-transactions" )
public String getInventoryTransactionsByAccount( @RequestParam( value = "account-id", required = true) long accountId,
Model model ){
model.addAttribute("transactions", inventoryService.findTransactionByAccountId( accountId ));
return "/cutting/inventory-transactions";
}
@GetMapping( "/inventory-summary" )
public String getInventorySummaryByAccount( @RequestParam( value = "account-id", required = true) long accountId, Model model ){
model.addAttribute("summaries", inventoryService.findItemSummaryByAccountId( accountId ));
return "/cutting/inventory-summary";
}
}

View File

@ -1,28 +1,53 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.JobCardRole;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.service.InventoryAccountService;
import com.utopiaindustries.service.JobCardService;
import com.utopiaindustries.service.LocationService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller
@JobCardRole
@RequestMapping( "/job-cards" )
public class JobCardController {
private final JobCardService jobCardService;
private final LocationService locationService;
private final InventoryAccountService inventoryAccountService;
public JobCardController(JobCardService jobCardService){
public JobCardController(JobCardService jobCardService, LocationService locationService, InventoryAccountService inventoryAccountService){
this.jobCardService = jobCardService;
this.locationService = locationService;
this.inventoryAccountService = inventoryAccountService;
}
/**
* get all job cards
* */
@GetMapping
public String showJobCardList( Model model ){
model.addAttribute("cards", jobCardService.getCards() );
public String showJobCardList( @RequestParam( value = "id", required = false ) String id,
@RequestParam( value = "code", required = false ) String code,
@RequestParam( value = "status", required = false ) String status,
@RequestParam( value = "inventory-status" , required = false) String inventoryStatus,
@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 = "created-start-date", required = false ) String createdStartDate,
@RequestParam( value = "created-end-date", required = false ) String createdEndDate,
@RequestParam( value = "limit" , required = false) Long limit,
Model model ){
List<JobCard> cards = jobCardService.getCards( id, code, status, inventoryStatus, customer, lotNumber, purchaseOrderId, locationSiteId,createdStartDate, createdEndDate, limit );
model.addAttribute("cards", cards );
model.addAttribute("statuses", JobCard.Status.values() );
model.addAttribute("invStatuses", JobCard.InventoryStatus.values() );
model.addAttribute("locations", locationService.findAll() );
return "job-card-list";
}
@ -30,14 +55,16 @@ public class JobCardController {
public String showJobCardForm( Model model ){
model.addAttribute("jobCard", jobCardService.createNewJobCard() );
model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() );
model.addAttribute("accounts", inventoryAccountService.getAllCuttingAccounts( ) );
return "job-card-add";
}
@GetMapping( value = "/edit/{id}" )
public String showJobCardEditForm( @PathVariable("id") long id,
Model model ){
model.addAttribute("jobCard", jobCardService.findCardRecursively( id ) );
model.addAttribute("jobCard", jobCardService.findCardRecursivelyForView( id ) );
model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() );
model.addAttribute("accounts", inventoryAccountService.getAllCuttingAccounts() );
return "job-card-edit";
}

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.PackagingRole;
import com.utopiaindustries.service.InventoryAccountService;
import com.utopiaindustries.service.LocationService;
import org.springframework.stereotype.Controller;
@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@PackagingRole
@RequestMapping("/packaging" )
public class PackagingController {

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.QCRole;
import com.utopiaindustries.model.ctp.FinishedItem;
import com.utopiaindustries.model.ctp.StitchedItemWrapper;
import com.utopiaindustries.service.BundleService;
@ -14,6 +15,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller
@QCRole
@RequestMapping( "/quality-control" )
public class QualityControlController {

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller;
import com.utopiaindustries.auth.StitchingRole;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.model.ctp.StitchingOfflineItem;
import com.utopiaindustries.service.*;
@ -14,6 +15,7 @@ import java.util.Arrays;
import java.util.List;
@Controller
@StitchingRole
@RequestMapping( "/stitching" )
public class StitchingController {

View File

@ -33,6 +33,7 @@ public class UserController {
model.addAttribute("user", userService.createEmptyUser() );
model.addAttribute("accounts", inventoryAccountService.findInventoryAccounts() );
model.addAttribute("roles", Roles.values() );
model.addAttribute("isNew", true );
return "_user-fragment";
}

View File

@ -26,6 +26,7 @@ public class InventoryAccountDAO {
private final String SELECT_BY_IDS_AND_PARENT_IDS = String.format( "SELECT * FROM %s WHERE id IN (:ids) AND parent_entity_id IN (:parent_entity_ids)", TABLE_NAME );
private final String SELECT_BY_IDS_AND_PARENT_ENTITY_TYPE_AND_PARENT_ID_AND_COUNT = String.format( "SELECT * FROM %s WHERE id IN (:ids) AND parent_entity_id = :parent_entity_id AND parent_entity_type = :parent_entity_type LIMIT :limit", TABLE_NAME );
private final String SELECT_BY_IDS_PACKAGING_AND_COUNT = String.format( "SELECT * FROM %s WHERE id IN (:ids) AND is_packaging = :is_packaging LIMIT :limit", TABLE_NAME );
private final String SELECT_BY_PARENT_TYPE_AND_PARENT_ID = String.format( "SELECT * FROM %s WHERE parent_entity_type = :parent_entity_type AND parent_entity_id = :parent_entity_id" , TABLE_NAME );
public InventoryAccountDAO(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
@ -136,4 +137,11 @@ public class InventoryAccountDAO {
public List<InventoryAccount> findByQuery( String query ){
return namedParameterJdbcTemplate.query( query, new InventoryAccountRowMapper() );
}
public List<InventoryAccount> findByParentEntityTypeAndParentId( String parentEntityType, Long parentEntityId ){
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("parent_entity_type" , parentEntityType );
params.addValue("parent_entity_id", parentEntityId );
return namedParameterJdbcTemplate.query( SELECT_BY_PARENT_TYPE_AND_PARENT_ID, params, new InventoryAccountRowMapper() );
}
}

View File

@ -25,6 +25,7 @@ public class JobCardDAO {
private final String INSERT_QUERY = String.format( "INSERT INTO %s (id, code, job_order_id, created_at, created_by, status, inventory_status, customer, lot_number, purchase_order_id, location_site_id, description) VALUES (:id, :code, :job_order_id, :created_at, :created_by, :status, :inventory_status, :customer, :lot_number, :purchase_order_id, :location_site_id, :description) ON DUPLICATE KEY UPDATE code = VALUES(code), job_order_id = VALUES(job_order_id), created_at = VALUES(created_at), created_by = VALUES(created_by), status = VALUES(status), inventory_status = VALUES(inventory_status), customer = VALUES(customer), lot_number = VALUES(lot_number), purchase_order_id = VALUES(purchase_order_id), location_site_id = VALUES(location_site_id), description = VALUES(description)", TABLE_NAME );
private final String SELECT_BY_LIKE_CODE_AND_INV_STATUS_AND_STATUS = String.format( "SELECT * FROM %s WHERE code like :code AND status = :status AND inventory_status = :inventory_status", TABLE_NAME );
private final String SELECT_BY_LIKE_CODE = String.format( "SELECT * FROM %s WHERE code like :code", TABLE_NAME );
private final String SELECT_BY_LIMIT = String.format( "SELECT * FROM %s WHERE created_by = :created_by ORDER BY id DESC limit :limit", TABLE_NAME );
// prepare query params
@ -98,4 +99,15 @@ public class JobCardDAO {
params.addValue("status", status );
return namedParameterJdbcTemplate.query(SELECT_BY_LIKE_CODE_AND_INV_STATUS_AND_STATUS, params, new JobCardRowMapper() );
}
public List<JobCard> findByUserAndLimit( String createdBy, Long limit ){
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("limit", limit.intValue() );
params.addValue("created_by", createdBy );
return namedParameterJdbcTemplate.query( SELECT_BY_LIMIT, params, new JobCardRowMapper() );
}
public List<JobCard> findByQuery( String query ){
return namedParameterJdbcTemplate.query( query, new JobCardRowMapper() );
}
}

View File

@ -10,6 +10,7 @@ import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Repository
public class JobCardItemDAO {
@ -21,7 +22,9 @@ public class JobCardItemDAO {
private final String SELECT_ALL_QUERY = String.format( "SELECT * FROM %s ORDER BY id DESC", TABLE_NAME );
private final String DELETE_QUERY = String.format( "DELETE FROM %s WHERE id = :id", TABLE_NAME );
private final String SELECT_BY_CARD_ID = String.format( "SELECT * FROM %s WHERE job_card_id = :card_id", TABLE_NAME );
private final String INSERT_QUERY = String.format( "INSERT INTO %s (id, job_card_id, item_id, sku, expected_production_quantity, total_production) VALUES (:id, :job_card_id, :item_id, :sku, :expected_production_quantity, :total_production) ON DUPLICATE KEY UPDATE job_card_id = VALUES(job_card_id), item_id = VALUES(item_id), sku = VALUES(sku), expected_production_quantity = VALUES(expected_production_quantity), total_production = VALUES(total_production)", TABLE_NAME );
private final String INSERT_QUERY = String.format( "INSERT INTO %s (id, job_card_id, item_id, sku, expected_production, actual_production, total_production, account_id, length, width, gsm, wt_ply, ply) VALUES (:id, :job_card_id, :item_id, :sku, :expected_production, :actual_production, :total_production, :account_id, :length, :width, :gsm, :wt_ply, :ply) ON DUPLICATE KEY UPDATE job_card_id = VALUES(job_card_id), item_id = VALUES(item_id), sku = VALUES(sku), expected_production = VALUES(expected_production), actual_production = VALUES(actual_production), total_production = VALUES(total_production), account_id = VALUES(account_id), length = VALUES(length), width = VALUES(width), gsm = VALUES(gsm), wt_ply = VALUES(wt_ply), ply = VALUES(ply) ", TABLE_NAME );
private final String SELECT_BY_IDS = String.format( "SELECT * FROM %s WHERE id IN (:ids)", TABLE_NAME );
private final String SELECT_BY_JOB_CARD_AND_ACCOUNT_IDS = String.format( "SELECT * FROM %s WHERE job_card_id = :job_card_id AND actual_production = :actual_production AND account_id IN (:account_ids)", TABLE_NAME );
public JobCardItemDAO(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
@ -34,8 +37,15 @@ public class JobCardItemDAO {
.addValue( "job_card_id", jobCardItem.getJobCardId() )
.addValue( "item_id", jobCardItem.getItemId() )
.addValue( "sku", jobCardItem.getSku() )
.addValue( "expected_production_quantity", jobCardItem.getExpectedProductionQuantity() )
.addValue("total_production", jobCardItem.getTotalProduction() );
.addValue( "expected_production", jobCardItem.getExpectedProduction() )
.addValue("actual_production", jobCardItem.getActualProduction() )
.addValue("total_production", jobCardItem.getTotalProduction() )
.addValue("account_id", jobCardItem.getAccountId() )
.addValue("length", jobCardItem.getLength() )
.addValue("width", jobCardItem.getWidth() )
.addValue("gsm", jobCardItem.getGsm() )
.addValue("wt_ply", jobCardItem.getWtPly() )
.addValue("ply", jobCardItem.getPly() );
return params;
}
@ -84,4 +94,19 @@ public class JobCardItemDAO {
params.addValue( "card_id", cardId );
return namedParameterJdbcTemplate.query(SELECT_BY_CARD_ID, params, new JobCardItemRowMapper() );
}
public List<JobCardItem> findByIds( List<Long> ids ){
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue( "ids", ids );
return namedParameterJdbcTemplate.query( SELECT_BY_IDS, params, new JobCardItemRowMapper() );
}
public List<JobCardItem> findByJobCardAndAccountIdsAndIsReceived( Long jobCardId, Long actualProduction, List<Long> accountIds ){
if( accountIds == null || accountIds.isEmpty() ) return new ArrayList<>();
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue( "account_ids", accountIds );
params.addValue("job_card_id", jobCardId );
params.addValue("actual_production", actualProduction );
return namedParameterJdbcTemplate.query( SELECT_BY_JOB_CARD_AND_ACCOUNT_IDS , params, new JobCardItemRowMapper() );
}
}

View File

@ -13,8 +13,15 @@ public class JobCardItemRowMapper implements RowMapper<JobCardItem> {
jobCardItem.setJobCardId( rs.getLong( "job_card_id" ) );
jobCardItem.setItemId( rs.getLong( "item_id" ) );
jobCardItem.setSku( rs.getString( "sku" ) );
jobCardItem.setExpectedProductionQuantity( rs.getBigDecimal( "expected_production_quantity" ) );
jobCardItem.setExpectedProduction( rs.getBigDecimal( "expected_production" ) );
jobCardItem.setActualProduction( rs.getBigDecimal("actual_production" ) );
jobCardItem.setTotalProduction( rs.getBigDecimal("total_production" ) );
jobCardItem.setAccountId( rs.getLong("account_id" ) );
jobCardItem.setLength( rs.getString("length" ) );
jobCardItem.setWidth( rs.getString("width") ) ;
jobCardItem.setGsm( rs.getString("gsm" ) );
jobCardItem.setWtPly( rs.getString("wt_ply" ) );
jobCardItem.setPly( rs.getString("ply" ) );
return jobCardItem;
}
}

View File

@ -3,8 +3,10 @@ package com.utopiaindustries.model;
public enum Roles {
ROLE_ADMIN,
ROLE_USER,
ROLE_JOB_CARD,
ROLE_CUTTING,
ROLE_STITCHING,
ROLE_QUALITY_CONTROL,
ROLE_FINISHING,
ROLE_PACKAGING
}

View File

@ -9,15 +9,24 @@ public class JobCardItem {
private long jobCardId;
private long itemId;
private String sku;
private BigDecimal expectedProductionQuantity;
private BigDecimal expectedProduction;
private BigDecimal actualProduction;
private BigDecimal totalProduction;
private long accountId;
private BigDecimal production;
private String length;
private String width;
private String gsm;
private String wtPly;
private String ply;
// wrapper
private List<CutPiece> cutPieces;
private String title;
private boolean isSelected;
public JobCardItem() {
this.expectedProductionQuantity = BigDecimal.ZERO;
this.expectedProduction = BigDecimal.ZERO;
this.actualProduction = BigDecimal.ZERO;
this.totalProduction = BigDecimal.ZERO;
this.production = BigDecimal.ZERO;
}
@ -54,12 +63,20 @@ public class JobCardItem {
this.sku = sku;
}
public BigDecimal getExpectedProductionQuantity() {
return expectedProductionQuantity;
public BigDecimal getExpectedProduction() {
return expectedProduction;
}
public void setExpectedProductionQuantity(BigDecimal expectedProductionQuantity) {
this.expectedProductionQuantity = expectedProductionQuantity;
public void setExpectedProduction(BigDecimal expectedProduction) {
this.expectedProduction = expectedProduction;
}
public BigDecimal getActualProduction() {
return actualProduction;
}
public void setActualProduction(BigDecimal actualProduction) {
this.actualProduction = actualProduction;
}
public List<CutPiece> getCutPieces() {
@ -86,6 +103,14 @@ public class JobCardItem {
this.totalProduction = totalProduction;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public BigDecimal getProduction() {
return production;
}
@ -94,6 +119,54 @@ public class JobCardItem {
this.production = production;
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getGsm() {
return gsm;
}
public void setGsm(String gsm) {
this.gsm = gsm;
}
public String getWtPly() {
return wtPly;
}
public void setWtPly(String wtPly) {
this.wtPly = wtPly;
}
public String getPly() {
return ply;
}
public void setPly(String ply) {
this.ply = ply;
}
public boolean getIsSelected() {
return isSelected;
}
public void setIsSelected(boolean selected) {
isSelected = selected;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -114,7 +187,15 @@ public class JobCardItem {
", jobCardId=" + jobCardId +
", itemId=" + itemId +
", sku='" + sku + '\'' +
", expectedProductionQuantity=" + expectedProductionQuantity +
", expectedProduction=" + expectedProduction +
", actualProduction=" + actualProduction +
", totalProduction=" + totalProduction +
", production=" + production +
", length='" + length + '\'' +
", width='" + width + '\'' +
", gsm='" + gsm + '\'' +
", wtPly='" + wtPly + '\'' +
", ply='" + ply + '\'' +
", cutPieces=" + cutPieces +
", title='" + title + '\'' +
'}';

View File

@ -0,0 +1,54 @@
package com.utopiaindustries.model.ctp;
import java.math.BigDecimal;
import java.util.List;
public class JobCardItemWrapper {
private long jobCardId;
private long jobCardItemId;
private List<CutPiece> pieces;
private BigDecimal actualProduction;
public long getJobCardId() {
return jobCardId;
}
public void setJobCardId(long jobCardId) {
this.jobCardId = jobCardId;
}
public long getJobCardItemId() {
return jobCardItemId;
}
public void setJobCardItemId(long jobCardItemId) {
this.jobCardItemId = jobCardItemId;
}
public List<CutPiece> getPieces() {
return pieces;
}
public void setPieces(List<CutPiece> pieces) {
this.pieces = pieces;
}
public BigDecimal getActualProduction() {
return actualProduction;
}
public void setActualProduction(BigDecimal actualProduction) {
this.actualProduction = actualProduction;
}
@Override
public String toString() {
return "JobCardItemWrapper{" +
"jobCardId=" + jobCardId +
", jobCardItemId=" + jobCardItemId +
", pieces=" + pieces +
", actualProduction=" + actualProduction +
'}';
}
}

View File

@ -0,0 +1,28 @@
package com.utopiaindustries.model.ctp;
import java.util.ArrayList;
import java.util.List;
public class JobCardWrapper {
public JobCardWrapper(){
this.items = new ArrayList<>();
}
private List<JobCardItemWrapper> items;
public List<JobCardItemWrapper> getItems() {
return items;
}
public void setItems(List<JobCardItemWrapper> items) {
this.items = items;
}
@Override
public String toString() {
return "JobCardWrapper{" +
"items=" + items +
'}';
}
}

View File

@ -0,0 +1,55 @@
package com.utopiaindustries.querybuilder.ctp;
import com.utopiaindustries.querybuilder.QueryBuilder;
import com.utopiaindustries.util.CTPDateTimeFormat;
import com.utopiaindustries.util.StringUtils;
import java.time.LocalDate;
public class JobCardQueryBuilder {
public static String buildQuery( String id, String code, String createdBy, String status, String inventoryStatus, String customer, String lotNumber, String purchaseOrderId, String locationSiteId, String startDate, String endDate, Long count ){
// format date
String formattedDate;
String formattedEndDate;
String startDate1 = "";
String endDate1 = "";
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() );
}
}
return ( new QueryBuilder() )
.setTable( "cut_to_pack.job_card" )
.setColumns( "*" )
.where()
.columnEquals( "id", id )
.and()
.columnEquals( "code", code )
.and()
.columnEquals( "status", status )
.and()
.columnEquals( "inventory_status", inventoryStatus )
.and()
.columnEquals( "customer", customer )
.and()
.columnEquals( "lot_number", lotNumber )
.and()
.columnEquals( "purchase_order_id", purchaseOrderId )
.and()
.columnEquals( "location_site_id", locationSiteId )
.and()
.columnEqualToOrGreaterThan("created_at" , startDate1 )
.and()
.columnEqualToOrLessThan( "created_at", endDate1 )
.limit( count.intValue() )
.build();
}
}

View File

@ -123,4 +123,8 @@ public class InventoryAccountService {
processIds.add(8L);
return inventoryAccountDAO.findByIdsAndProcessIds( userInventoryAccountIds, processIds );
}
public List<InventoryAccount> getAllCuttingAccounts(){
return inventoryAccountDAO.findByParentEntityTypeAndParentId( "PROCESS", 1L );
}
}

View File

@ -28,7 +28,7 @@ public class InventoryService {
private final FinishedItemDAO finishedItemDAO;
private final StitchingOfflineItemDAO stitchingOfflineItemDAO;
public InventoryService(JobCardItemDAO jobCardItemDAO, CutPieceDAO cutPieceDAO, BundleDAO bundleDAO, InventoryTransactionLegDAO inventoryTransactionLegDAO, InventoryTransactionDAO inventoryTransactionDAO, JobCardDAO jobCardDAO, CryptographyService cryptographyService, MasterBundleDAO masterBundleDAO, FinishedItemDAO finishedItemDAO, StitchingOfflineItemDAO stitchingOfflineItemDAO) {
public InventoryService( JobCardItemDAO jobCardItemDAO, CutPieceDAO cutPieceDAO, BundleDAO bundleDAO, InventoryTransactionLegDAO inventoryTransactionLegDAO, InventoryTransactionDAO inventoryTransactionDAO, JobCardDAO jobCardDAO, CryptographyService cryptographyService, MasterBundleDAO masterBundleDAO, FinishedItemDAO finishedItemDAO, StitchingOfflineItemDAO stitchingOfflineItemDAO) {
this.jobCardItemDAO = jobCardItemDAO;
this.cutPieceDAO = cutPieceDAO;
this.bundleDAO = bundleDAO;
@ -41,60 +41,77 @@ public class InventoryService {
this.stitchingOfflineItemDAO = stitchingOfflineItemDAO;
}
private void updateJobCardInventoryStatus( JobCard card ){
List<JobCardItem> items = jobCardItemDAO.findByCardId( card.getId( ) );
for( JobCardItem item : items ){
// check if item is received
if( item.getActualProduction( ) == null || item.getActualProduction( ).compareTo( BigDecimal.ZERO ) == 0 ){
return;
}
}
card.setInventoryStatus( JobCard.InventoryStatus.RECEIVED.name( ) );
jobCardDAO.save( card );
}
/*
* receive inv from job card
* */
@Transactional(rollbackFor = Exception.class)
public void receiveJobCardInventory(long jobCardId, long accountId) {
if (jobCardId == 0 || accountId == 0) {
throw new RuntimeException("JobCard | Account can`t be empty");
@Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void receiveJobCardInventory( long jobCardId, JobCardWrapper jobCardWrapper ) {
if ( jobCardId == 0 || jobCardWrapper.getItems( ) == null || jobCardWrapper.getItems( ).isEmpty( ) ) {
throw new RuntimeException( " JobCard can`t be empty");
}
JobCard jobCard = jobCardDAO.find(jobCardId);
JobCard jobCard = jobCardDAO.find( jobCardId );
// get job cad items
List<JobCardItem> items = jobCardItemDAO.findByCardId(jobCardId);
if (items != null && !items.isEmpty()) {
// get job card ite ids
List<Long> jobCardItemIds = items.stream()
.map(JobCardItem::getId)
.collect(Collectors.toList());
List<JobCardItemWrapper> jobCardItemWrappers = jobCardWrapper.getItems( );
List<Long> jobCardItemWrapperIds = jobCardItemWrappers.stream( )
.map( JobCardItemWrapper::getJobCardItemId )
.collect( Collectors.toList( ) );
// id to item map
Map<Long, JobCardItem> idToItemMap = items.stream()
.collect(Collectors.toMap(JobCardItem::getId, Function.identity()));
Map<Long,BigDecimal> jobCardItemIdToActualProdMap = jobCardItemWrappers.stream( )
.collect( Collectors.toMap( JobCardItemWrapper::getJobCardItemId, JobCardItemWrapper::getActualProduction ) );
Map<Long, List<CutPiece>> piecesMap = cutPieceDAO.findByJobCardItemIds(jobCardItemIds)
.stream()
.collect(Collectors.groupingBy(CutPiece::getJobCardItemId));
List<JobCardItem> items = jobCardItemDAO.findByIds( jobCardItemWrapperIds );
if ( items != null && !items.isEmpty( ) ) {
// get job card item ids
List<Long> jobCardItemIds = items.stream( )
.map( JobCardItem::getId)
.collect( Collectors.toList( ));
// populate map
Map<JobCardItem, List<CutPiece>> jobCardItemtoPiecesMap = new HashMap<>();
for (JobCardItem jobCardItem : items) {
if (!jobCardItemtoPiecesMap.containsKey(jobCardItem)) {
jobCardItemtoPiecesMap.put(jobCardItem, piecesMap.getOrDefault(jobCardItem.getId(), new ArrayList<>()));
}
// save updated cut pieces
List<CutPiece> cutPieces = jobCardItemWrappers.stream( )
.flatMap( wrapper -> wrapper.getPieces( ).stream( ) )
.collect( Collectors.toList( ) );
cutPieceDAO.saveAll( cutPieces );
Map<Long, List<CutPiece>> piecesMap = cutPieceDAO.findByJobCardItemIds( jobCardItemIds)
.stream( )
.collect( Collectors.groupingBy( CutPiece::getJobCardItemId));
for ( JobCardItem jobCardItem : items) {
// create + save bundles
List<Bundle> bundles = createBundles( jobCardItem, piecesMap.get( jobCardItem.getId( ) ) );
// create transactions
createTransactions( bundles, jobCardItem.getAccountId( ), InventoryArtifactType.BUNDLE.name( ));
jobCardItem.setActualProduction( jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ) , BigDecimal.ZERO ) );
}
// create + save bundles
List<Bundle> bundles = createBundles(jobCardId, jobCardItemtoPiecesMap);
// create transactions
createTransactions(bundles, accountId, InventoryArtifactType.BUNDLE.name());
// update items with quantity
jobCardItemDAO.saveAll( items );
// update job card inv status
jobCard.setInventoryStatus(JobCard.InventoryStatus.RECEIVED.name());
jobCardDAO.save(jobCard);
updateJobCardInventoryStatus( jobCard );
} else {
throw new RuntimeException("Items Not found in Job Card");
throw new RuntimeException( "Items Not found in Job Card");
}
}
/*
* t create transactions
* */
private void createTransactions(List<? extends InventoryArtifact> artifacts, long accountId, String parentDocumentType) {
if (!artifacts.isEmpty()) {
InventoryTransaction transaction = createInventoryTransaction("Transaction Against " + parentDocumentType);
for (InventoryArtifact artifact : artifacts) {
InventoryTransactionLeg leg = createInventoryTransactionLeg(transaction, artifact, accountId, InventoryTransactionLeg.Type.IN.name(), parentDocumentType);
private void createTransactions( List<? extends InventoryArtifact> artifacts, long accountId, String parentDocumentType) {
if ( !artifacts.isEmpty( )) {
InventoryTransaction transaction = createInventoryTransaction( "Transaction Against " + parentDocumentType);
for ( InventoryArtifact artifact : artifacts) {
InventoryTransactionLeg leg = createInventoryTransactionLeg( transaction, artifact, accountId, InventoryTransactionLeg.Type.IN.name( ), parentDocumentType );
}
}
}
@ -103,167 +120,169 @@ public class InventoryService {
/*
* create and save transaction
* */
private InventoryTransaction createInventoryTransaction(String notes) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
InventoryTransaction transaction = new InventoryTransaction();
transaction.setGeneratedBy(authentication.getName());
transaction.setTransactionDateTime(LocalDateTime.now());
transaction.setNotes(notes);
transaction.setId(inventoryTransactionDAO.save(transaction));
private InventoryTransaction createInventoryTransaction( String notes) {
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
InventoryTransaction transaction = new InventoryTransaction( );
transaction.setGeneratedBy( authentication.getName( ));
transaction.setTransactionDateTime( LocalDateTime.now( ));
transaction.setNotes( notes);
transaction.setId( inventoryTransactionDAO.save( transaction));
return transaction;
}
/*
* create and save inventory transaction
* */
private InventoryTransactionLeg createInventoryTransactionLeg(InventoryTransaction transaction,
private InventoryTransactionLeg createInventoryTransactionLeg( InventoryTransaction transaction,
InventoryArtifact artifact,
long accountId,
String transactionType,
String parentDocumentType) {
InventoryTransactionLeg inventoryTransactionLeg = new InventoryTransactionLeg();
inventoryTransactionLeg.setTransactionId(transaction.getId());
inventoryTransactionLeg.setType(transactionType);
inventoryTransactionLeg.setQuantity(BigDecimal.valueOf(1L));
inventoryTransactionLeg.setAccountId((int) accountId);
inventoryTransactionLeg.setItemId(artifact.getItemId());
inventoryTransactionLeg.setSku(artifact.getSku());
inventoryTransactionLeg.setParentDocumentType(parentDocumentType);
inventoryTransactionLeg.setParentDocumentId(artifact.getId());
inventoryTransactionLeg.setParentDocumentPieceType(artifact.getType());
inventoryTransactionLeg.setTransactionLegDateTime(LocalDateTime.now());
InventoryTransactionLeg inventoryTransactionLeg = new InventoryTransactionLeg( );
inventoryTransactionLeg.setTransactionId( transaction.getId( ));
inventoryTransactionLeg.setType( transactionType);
inventoryTransactionLeg.setQuantity( BigDecimal.valueOf( 1L));
inventoryTransactionLeg.setAccountId( ( int) accountId);
inventoryTransactionLeg.setItemId( artifact.getItemId( ));
inventoryTransactionLeg.setSku( artifact.getSku( ));
inventoryTransactionLeg.setParentDocumentType( parentDocumentType);
inventoryTransactionLeg.setParentDocumentId( artifact.getId( ));
inventoryTransactionLeg.setParentDocumentPieceType( artifact.getType( ));
inventoryTransactionLeg.setTransactionLegDateTime( LocalDateTime.now( ));
// set balance
BigDecimal initialBalance = calculateBalance(accountId, artifact.getItemId(), parentDocumentType, artifact.getType());
BigDecimal initialBalance = calculateBalance( accountId, artifact.getItemId( ), parentDocumentType, artifact.getType( ));
if (transactionType.equalsIgnoreCase(InventoryTransactionLeg.Type.IN.name())) {
initialBalance = initialBalance.add(inventoryTransactionLeg.getQuantity());
if ( transactionType.equalsIgnoreCase( InventoryTransactionLeg.Type.IN.name( ))) {
initialBalance = initialBalance.add( inventoryTransactionLeg.getQuantity( ));
} else {
initialBalance = initialBalance.subtract(inventoryTransactionLeg.getQuantity());
initialBalance = initialBalance.subtract( inventoryTransactionLeg.getQuantity( ));
}
inventoryTransactionLeg.setBalance(initialBalance);
inventoryTransactionLeg.setId(inventoryTransactionLegDAO.save(inventoryTransactionLeg));
inventoryTransactionLeg.setBalance( initialBalance);
inventoryTransactionLeg.setId( inventoryTransactionLegDAO.save( inventoryTransactionLeg));
return inventoryTransactionLeg;
}
// calculate balance
private BigDecimal calculateBalance(long accountId, long itemId, String parentType, String pieceType) {
private BigDecimal calculateBalance( long accountId, long itemId, String parentType, String pieceType) {
// find the last transaction leg of the current account Id with itemId
InventoryTransactionLeg lastTransactionLeg = inventoryTransactionLegDAO.findLastByAccountIdAndItemIdAndParentType(accountId, itemId, parentType, pieceType);
if (lastTransactionLeg.getBalance() != null) {
return lastTransactionLeg.getBalance();
InventoryTransactionLeg lastTransactionLeg = inventoryTransactionLegDAO.findLastByAccountIdAndItemIdAndParentType( accountId, itemId, parentType, pieceType);
if ( lastTransactionLeg.getBalance( ) != null) {
return lastTransactionLeg.getBalance( );
}
return BigDecimal.ZERO;
}
// create bundles from cut pieces
private List<Bundle> createBundles(long jobCardId, Map<JobCardItem, List<CutPiece>> jobCardItemtoPiecesMap) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (jobCardItemtoPiecesMap != null && !jobCardItemtoPiecesMap.isEmpty()) {
List<Bundle> bundles = new ArrayList<>();
for (Map.Entry<JobCardItem, List<CutPiece>> entry : jobCardItemtoPiecesMap.entrySet()) {
JobCardItem key = entry.getKey();
List<CutPiece> value = entry.getValue();
// create bundle against every cut piece
for (CutPiece cutPiece : value) {
Bundle bundle = new Bundle();
bundle.setItemId(key.getItemId());
bundle.setSku(key.getSku());
bundle.setJobCardId(jobCardId);
bundle.setWrapQuantity(cutPiece.getQuantity());
bundle.setType(cutPiece.getType());
bundle.setCreatedAt(LocalDateTime.now());
bundle.setCreatedBy(authentication.getName());
bundles.add(bundle);
bundle.setId(bundleDAO.save(bundle));
bundle.setBarcode(cryptographyService.generateRandomString(15));
// save again after barcode generation
bundle.setId(bundleDAO.save(bundle));
}
private List<Bundle> createBundles( JobCardItem jobCardItem,
List<CutPiece> jobCardItemPieces ) {
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
if ( jobCardItemPieces != null && !jobCardItemPieces.isEmpty( )) {
List<Bundle> bundles = new ArrayList<>( );
// create bundle against every cut piece
for ( CutPiece cutPiece : jobCardItemPieces ) {
Bundle bundle = new Bundle( );
bundle.setItemId( jobCardItem.getItemId( ));
bundle.setSku( jobCardItem.getSku( ));
bundle.setJobCardId( jobCardItem.getJobCardId( ) );
bundle.setWrapQuantity( cutPiece.getQuantity( ));
bundle.setType( cutPiece.getType( ));
bundle.setCreatedAt( LocalDateTime.now( ));
bundle.setCreatedBy( authentication.getName( ));
bundles.add( bundle);
bundle.setId( bundleDAO.save( bundle));
bundle.setBarcode( cryptographyService.generateRandomString( 15));
// save again after barcode generation
bundle.setId( bundleDAO.save( bundle));
}
// for ( Map.Entry<JobCardItem, List<CutPiece>> entry : jobCardItemPieces ) {
// JobCardItem key = entry.getKey( );
// List<CutPiece> value = entry.getValue( );
//
//
// }
return bundles;
}
return new ArrayList<>();
return new ArrayList<>( );
}
/*
* receive inventory from master barcode
* */
@Transactional(rollbackFor = Exception.class)
public void receiveInventoryFromMasterBarcode(long masterId, long toAccount) {
if (masterId == 0 || toAccount == 0) {
throw new RuntimeException("Master Barcode | Account can`t be empty");
@Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void receiveInventoryFromMasterBarcode( long masterId, long toAccount) {
if ( masterId == 0 || toAccount == 0) {
throw new RuntimeException( "Master Barcode | Account can`t be empty");
}
MasterBundle masterBundle = masterBundleDAO.find(masterId);
MasterBundle masterBundle = masterBundleDAO.find( masterId);
// find bundles from master barcode
List<Bundle> bundles = bundleDAO.findByMasterId(masterId);
if (bundles != null && !bundles.isEmpty()) {
List<Bundle> bundles = bundleDAO.findByMasterId( masterId);
if ( bundles != null && !bundles.isEmpty( )) {
// bundle ids
List<Long> bundleIds = bundles.stream().map(Bundle::getId).collect(Collectors.toList());
List<Long> bundleIds = bundles.stream( ).map( Bundle::getId).collect( Collectors.toList( ));
Map<Long, InventoryTransactionLeg> lastBundleIdInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), bundleIds, InventoryArtifactType.BUNDLE.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), bundleIds, InventoryArtifactType.BUNDLE.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// create Transaction
InventoryTransaction transaction = createInventoryTransaction("Against Movement from Cutting to Stitching");
inventoryTransactionDAO.save(transaction);
InventoryTransaction transaction = createInventoryTransaction( "Against Movement from Cutting to Stitching");
inventoryTransactionDAO.save( transaction);
// create transaction legs
for (Bundle bundle : bundles) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault(bundle.getId(), null);
if (lastInvTransaction != null) {
for ( Bundle bundle : bundles) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault( bundle.getId( ), null);
if ( lastInvTransaction != null) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, bundle, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.BUNDLE.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, bundle, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.BUNDLE.name( ));
// IN
createInventoryTransactionLeg(transaction, bundle, toAccount, InventoryTransactionLeg.Type.IN.name(), InventoryArtifactType.BUNDLE.name());
createInventoryTransactionLeg( transaction, bundle, toAccount, InventoryTransactionLeg.Type.IN.name( ), InventoryArtifactType.BUNDLE.name( ));
}
}
// update status
masterBundle.setIsReceived(true);
masterBundleDAO.save(masterBundle);
masterBundle.setIsReceived( true);
masterBundleDAO.save( masterBundle);
}
}
private void validateItems(List<JobCardItem> cardItems) {
if (cardItems == null || cardItems.isEmpty()) {
throw new RuntimeException("Item cant be Empty | null");
private void validateItems( List<JobCardItem> cardItems) {
if ( cardItems == null || cardItems.isEmpty( )) {
throw new RuntimeException( "Item cant be Empty | null");
}
for (JobCardItem jobCardItem : cardItems) {
int finalQuantity = jobCardItem.getExpectedProductionQuantity().compareTo(jobCardItem.getTotalProduction().add(jobCardItem.getProduction()));
if (finalQuantity < 0) {
throw new RuntimeException(" Items cant be generated because it exceeds from limit of expected Production");
for ( JobCardItem jobCardItem : cardItems) {
int finalQuantity = jobCardItem.getActualProduction( ).compareTo( jobCardItem.getTotalProduction( ).add( jobCardItem.getProduction( )));
if ( finalQuantity < 0) {
throw new RuntimeException( " Items cant be generated because it exceeds from limit of expected Production");
}
}
}
private void checkAllBundleAreReceived(long jobCardId,
private void checkAllBundleAreReceived( long jobCardId,
List<JobCardItem> jobCardItems) {
if (jobCardItems != null && !jobCardItems.isEmpty()) {
List<Long> itemIds = jobCardItems.stream().map(JobCardItem::getItemId).collect(Collectors.toList());
List<Bundle> bundles = bundleDAO.findByItemIdsAndCardId(itemIds, jobCardId);
List<Long> masterBundleIds = bundles.stream().map(Bundle::getMasterBundleId).collect(Collectors.toList());
// Map<String,List<Bundle>> ItemIdCardIdToBundlesMap = bundles
// .stream()
// .collect( Collectors.groupingBy( e-> e.getItemId() + "-" + e.getJobCardId() ) );
if ( jobCardItems != null && !jobCardItems.isEmpty( ) ) {
List<Long> itemIds = jobCardItems.stream( )
.filter( JobCardItem::getIsSelected )
.map( JobCardItem::getItemId).collect( Collectors.toList( ));
List<Bundle> bundles = bundleDAO.findByItemIdsAndCardId( itemIds, jobCardId);
List<Long> masterBundleIds = bundles.stream( ).map( Bundle::getMasterBundleId).collect( Collectors.toList( ));
Map<Long, MasterBundle> idToMasterBundleMap = masterBundleDAO.findByIds( masterBundleIds)
.stream( )
.collect( Collectors.toMap( MasterBundle::getId, Function.identity( )));
Map<Long, MasterBundle> idToMasterBundleMap = masterBundleDAO.findByIds(masterBundleIds)
.stream()
.collect(Collectors.toMap(MasterBundle::getId, Function.identity()));
for (Bundle bundle : bundles) {
for ( Bundle bundle : bundles) {
// check all bundles are received
MasterBundle masterBundle = idToMasterBundleMap.getOrDefault(bundle.getMasterBundleId(), null);
if (masterBundle == null || !masterBundle.getIsReceived()) {
throw new RuntimeException("Please Receive Bundles Against Master Bundles First to Create Finished Item");
MasterBundle masterBundle = idToMasterBundleMap.getOrDefault( bundle.getMasterBundleId( ), null);
if ( masterBundle == null || ! masterBundle.getIsReceived( ) ) {
throw new RuntimeException( "Please Receive Bundles Against Master Bundles First to Create Finished Item");
}
}
}
@ -272,76 +291,76 @@ public class InventoryService {
/*
* create finished items from master bundles
* */
@Transactional(rollbackFor = Exception.class)
public void createStitchingOfflineItemsFromJobCard(JobCard jobCard) {
List<JobCardItem> jobCardItems = jobCard.getItems();
List<JobCardItem> updatedItems = new ArrayList<>();
@Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void createStitchingOfflineItemsFromJobCard( JobCard jobCard) {
List<JobCardItem> jobCardItems = jobCard.getItems( );
List<JobCardItem> updatedItems = new ArrayList<>( );
// validate items
validateItems(jobCardItems);
validateItems( jobCardItems);
// check whether all bundles are received against finish goods
checkAllBundleAreReceived(jobCard.getId(), jobCardItems);
for (JobCardItem item : jobCardItems) {
checkAllBundleAreReceived( jobCard.getId( ), jobCardItems);
for ( JobCardItem item : jobCardItems) {
// select which has inventory
if (!item.getProduction().equals(BigDecimal.ZERO)) {
if ( item.getProduction( ).compareTo( BigDecimal.ZERO ) != 0 ) {
// production is completed out bundles
if (item.getExpectedProductionQuantity().compareTo(item.getTotalProduction().add(item.getProduction())) == 0) {
if ( item.getActualProduction( ).compareTo( item.getTotalProduction( ).add( item.getProduction( ))) == 0) {
// create out transactions of bundles in master bundles
List<Bundle> bundles = bundleDAO.findByItemIdAndCardId(item.getItemId(), jobCard.getId());
if (bundles != null && !bundles.isEmpty()) {
List<Bundle> bundles = bundleDAO.findByItemIdAndCardId( item.getItemId( ), jobCard.getId( ));
if ( bundles != null && !bundles.isEmpty( )) {
// bundle ids
List<Long> bundleIds = bundles.stream().map(Bundle::getId).collect(Collectors.toList());
List<Long> bundleIds = bundles.stream( ).map( Bundle::getId).collect( Collectors.toList( ));
Map<Long, InventoryTransactionLeg> lastBundleIdInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), bundleIds, InventoryArtifactType.BUNDLE.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), bundleIds, InventoryArtifactType.BUNDLE.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// create Transaction
InventoryTransaction transaction = createInventoryTransaction("Against Movement from Stitching to Stitched Offline Item");
inventoryTransactionDAO.save(transaction);
InventoryTransaction transaction = createInventoryTransaction( "Against Movement from Stitching to Stitched Offline Item");
inventoryTransactionDAO.save( transaction);
// create transaction legs
for (Bundle bundle : bundles) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault(bundle.getId(), null);
if (lastInvTransaction != null) {
for ( Bundle bundle : bundles) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault( bundle.getId( ), null);
if ( lastInvTransaction != null) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, bundle, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.BUNDLE.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, bundle, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.BUNDLE.name( ));
}
}
}
}
// create finished items
List<StitchingOfflineItem> stitchingOfflineItems = createStitchingOfflineItems(item);
List<StitchingOfflineItem> stitchingOfflineItems = createStitchingOfflineItems( item);
// create IN Transactions of Finished Items into account
createTransactions(stitchingOfflineItems, jobCard.getToAccountId(), InventoryArtifactType.STITCHING_OFFLINE.name());
item.setTotalProduction(item.getTotalProduction().add(item.getProduction()));
item.setJobCardId(jobCard.getId());
updatedItems.add(item);
createTransactions( stitchingOfflineItems, jobCard.getToAccountId( ), InventoryArtifactType.STITCHING_OFFLINE.name( ));
item.setTotalProduction( item.getTotalProduction( ).add( item.getProduction( )));
item.setJobCardId( jobCard.getId( ));
updatedItems.add( item);
}
}
// save all
jobCardItemDAO.saveAll(updatedItems);
jobCardItemDAO.saveAll( updatedItems);
}
/*
* create finished items
* */
public List<StitchingOfflineItem> createStitchingOfflineItems(JobCardItem jobCardItem) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
List<StitchingOfflineItem> items = new ArrayList<>();
if (jobCardItem != null) {
for (int i = 1; i <= jobCardItem.getProduction().intValue(); i++) {
StitchingOfflineItem stitchingOfflineItem = new StitchingOfflineItem();
stitchingOfflineItem.setCreatedAt(LocalDateTime.now());
stitchingOfflineItem.setCreatedBy(authentication.getName());
stitchingOfflineItem.setItemId(jobCardItem.getItemId());
stitchingOfflineItem.setSku(jobCardItem.getSku());
stitchingOfflineItem.setJobCardId(jobCardItem.getId());
stitchingOfflineItem.setIsQa(true);
long id = stitchingOfflineItemDAO.save(stitchingOfflineItem);
stitchingOfflineItem.setId(id);
stitchingOfflineItem.setBarcode(cryptographyService.generateRandomString(15));
stitchingOfflineItemDAO.save(stitchingOfflineItem);
items.add(stitchingOfflineItem);
public List<StitchingOfflineItem> createStitchingOfflineItems( JobCardItem jobCardItem) {
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
List<StitchingOfflineItem> items = new ArrayList<>( );
if ( jobCardItem != null) {
for ( int i = 1; i <= jobCardItem.getProduction( ).intValue( ); i++) {
StitchingOfflineItem stitchingOfflineItem = new StitchingOfflineItem( );
stitchingOfflineItem.setCreatedAt( LocalDateTime.now( ));
stitchingOfflineItem.setCreatedBy( authentication.getName( ));
stitchingOfflineItem.setItemId( jobCardItem.getItemId( ));
stitchingOfflineItem.setSku( jobCardItem.getSku( ));
stitchingOfflineItem.setJobCardId( jobCardItem.getId( ));
stitchingOfflineItem.setIsQa( false );
long id = stitchingOfflineItemDAO.save( stitchingOfflineItem);
stitchingOfflineItem.setId( id);
stitchingOfflineItem.setBarcode( cryptographyService.generateRandomString( 15));
stitchingOfflineItemDAO.save( stitchingOfflineItem);
items.add( stitchingOfflineItem);
}
}
return items;
@ -350,51 +369,51 @@ public class InventoryService {
/*
* find transactions by account id
* */
public List<InventoryTransactionLeg> findTransactionByAccountId(long accountId) {
List<InventoryTransactionLeg> legs = inventoryTransactionLegDAO.findByAccountId(accountId);
public List<InventoryTransactionLeg> findTransactionByAccountId( long accountId) {
List<InventoryTransactionLeg> legs = inventoryTransactionLegDAO.findByAccountId( accountId);
List<Long> tIds = legs.stream().map(InventoryTransactionLeg::getTransactionId).collect(Collectors.toList());
Map<Long, InventoryTransaction> idToTransactioMap = inventoryTransactionDAO.findByIds(tIds).stream().collect(Collectors.toMap(InventoryTransaction::getId, Function.identity()));
legs.forEach(leg -> leg.setTransaction(idToTransactioMap.get(leg.getTransactionId())));
List<Long> tIds = legs.stream( ).map( InventoryTransactionLeg::getTransactionId).collect( Collectors.toList( ));
Map<Long, InventoryTransaction> idToTransactioMap = inventoryTransactionDAO.findByIds( tIds).stream( ).collect( Collectors.toMap( InventoryTransaction::getId, Function.identity( )));
legs.forEach( leg -> leg.setTransaction( idToTransactioMap.get( leg.getTransactionId( ))));
return legs;
}
/*
*
* */
@Transactional(rollbackFor = Exception.class)
public void markFinishedItemsApproved(List<Long> fItemIds, long toAccount) {
@Transactional( rollbackFor = Exception.class)
public void markFinishedItemsApproved( List<Long> fItemIds, long toAccount) {
if (fItemIds.isEmpty() || toAccount == 0) {
throw new RuntimeException("Finished Item Ids | Account can`t be empty");
if ( fItemIds.isEmpty( ) || toAccount == 0) {
throw new RuntimeException( "Finished Item Ids | Account can`t be empty");
}
List<FinishedItem> finishedItems = finishedItemDAO.findByIds(fItemIds);
if (finishedItems != null && !finishedItems.isEmpty()) {
List<FinishedItem> finishedItems = finishedItemDAO.findByIds( fItemIds);
if ( finishedItems != null && !finishedItems.isEmpty( )) {
// bundle ids
List<Long> finishedItemIds = finishedItems.stream().map(FinishedItem::getId).collect(Collectors.toList());
List<Long> finishedItemIds = finishedItems.stream( ).map( FinishedItem::getId).collect( Collectors.toList( ));
Map<Long, InventoryTransactionLeg> lastBundleIdInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), finishedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), finishedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// create Transaction
InventoryTransaction transaction = createInventoryTransaction("Against Movement from Stitching to Packaging After QA");
inventoryTransactionDAO.save(transaction);
InventoryTransaction transaction = createInventoryTransaction( "Against Movement from Stitching to Packaging After QA");
inventoryTransactionDAO.save( transaction);
// create transaction legs
for (FinishedItem finishedItem : finishedItems) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault(finishedItem.getId(), null);
if (lastInvTransaction != null) {
for ( FinishedItem finishedItem : finishedItems) {
InventoryTransactionLeg lastInvTransaction = lastBundleIdInTransactionMap.getOrDefault( finishedItem.getId( ), null);
if ( lastInvTransaction != null) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.STITCHING_OFFLINE.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.STITCHING_OFFLINE.name( ));
// IN
createInventoryTransactionLeg(transaction, finishedItem, toAccount, InventoryTransactionLeg.Type.IN.name(), InventoryArtifactType.STITCHING_OFFLINE.name());
createInventoryTransactionLeg( transaction, finishedItem, toAccount, InventoryTransactionLeg.Type.IN.name( ), InventoryArtifactType.STITCHING_OFFLINE.name( ));
}
finishedItem.setIsQa(true);
finishedItem.setIsQa( true);
}
finishedItemDAO.saveAll(finishedItems);
finishedItemDAO.saveAll( finishedItems);
}
}
@ -402,81 +421,81 @@ public class InventoryService {
/*
* generate finished items against stitched items
* */
@Transactional(rollbackFor = Exception.class)
public void createFinishedItemsAgainstStitchedItems( StitchedItemWrapper wrapper ) {
if (wrapper.getItems() != null && wrapper.getFinishedAccountId() != 0) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@Transactional( rollbackFor = Exception.class)
public void createFinishedItemsAgainstStitchedItems( StitchedItemWrapper wrapper ) {
if ( wrapper.getItems( ) != null && wrapper.getFinishedAccountId( ) != 0) {
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
List<StitchingOfflineItem> stitchingOfflineItems = wrapper.getItems();
List<StitchingOfflineItem> updatedStitchedItems = new ArrayList<>();
List<FinishedItem> finishedItems = new ArrayList<>();
List<StitchingOfflineItem> stitchingOfflineItems = wrapper.getItems( );
List<StitchingOfflineItem> updatedStitchedItems = new ArrayList<>( );
List<FinishedItem> finishedItems = new ArrayList<>( );
List<Long> stitchedItemIds = stitchingOfflineItems.stream()
.map(StitchingOfflineItem::getId)
.collect(Collectors.toList());
List<Long> stitchedItemIds = stitchingOfflineItems.stream( )
.map( StitchingOfflineItem::getId)
.collect( Collectors.toList( ));
Map<Long, InventoryTransactionLeg> lastStitchedIdInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), stitchedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), stitchedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// get finished items from stitched items i f exists
List<Long> preCreatedFinishedItemIds = finishedItemDAO.findByStitchedItemIds( stitchedItemIds ).stream().
map( FinishedItem::getId ).collect(Collectors.toList());
List<Long> preCreatedFinishedItemIds = finishedItemDAO.findByStitchedItemIds( stitchedItemIds ).stream( ).
map( FinishedItem::getId ).collect( Collectors.toList( ));
Map<Long, InventoryTransactionLeg> lastFinishedItemInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), preCreatedFinishedItemIds, InventoryArtifactType.FINISHED_ITEM.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), preCreatedFinishedItemIds, InventoryArtifactType.FINISHED_ITEM.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
InventoryTransaction transaction = createInventoryTransaction("Against Movement From Stitching Offline to Finished Item");
InventoryTransaction transaction = createInventoryTransaction( "Against Movement From Stitching Offline to Finished Item");
// generate FI for SI
for (StitchingOfflineItem stitchingOfflineItem : stitchingOfflineItems) {
if (stitchingOfflineItem.getQaStatus().equalsIgnoreCase("APPROVED" )) {
for ( StitchingOfflineItem stitchingOfflineItem : stitchingOfflineItems) {
if ( stitchingOfflineItem.getQaStatus( ).equalsIgnoreCase( "APPROVED" )) {
// check finished item is already created
FinishedItem preCreatedItem = finishedItemDAO.findByStitchedItem(stitchingOfflineItem.getId());
if (preCreatedItem == null) {
FinishedItem finishedItem = new FinishedItem();
finishedItem.setItemId(stitchingOfflineItem.getItemId());
finishedItem.setSku(stitchingOfflineItem.getSku());
finishedItem.setBarcode(stitchingOfflineItem.getBarcode());
finishedItem.setCreatedBy(authentication.getName());
finishedItem.setCreatedAt(LocalDateTime.now());
finishedItem.setStitchedItemId(stitchingOfflineItem.getId());
finishedItem.setJobCardId(stitchingOfflineItem.getJobCardId());
finishedItem.setIsQa(false);
finishedItem.setId(finishedItemDAO.save(finishedItem));
finishedItems.add(finishedItem);
InventoryTransactionLeg lastInvTransaction = lastStitchedIdInTransactionMap.getOrDefault(stitchingOfflineItem.getId(), null);
if ( lastInvTransaction != null ) {
FinishedItem preCreatedItem = finishedItemDAO.findByStitchedItem( stitchingOfflineItem.getId( ));
if ( preCreatedItem == null) {
FinishedItem finishedItem = new FinishedItem( );
finishedItem.setItemId( stitchingOfflineItem.getItemId( ));
finishedItem.setSku( stitchingOfflineItem.getSku( ));
finishedItem.setBarcode( stitchingOfflineItem.getBarcode( ));
finishedItem.setCreatedBy( authentication.getName( ));
finishedItem.setCreatedAt( LocalDateTime.now( ));
finishedItem.setStitchedItemId( stitchingOfflineItem.getId( ));
finishedItem.setJobCardId( stitchingOfflineItem.getJobCardId( ));
finishedItem.setIsQa( false);
finishedItem.setId( finishedItemDAO.save( finishedItem));
finishedItems.add( finishedItem);
InventoryTransactionLeg lastInvTransaction = lastStitchedIdInTransactionMap.getOrDefault( stitchingOfflineItem.getId( ), null);
if ( lastInvTransaction != null ) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, stitchingOfflineItem, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.STITCHING_OFFLINE.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, stitchingOfflineItem, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.STITCHING_OFFLINE.name( ));
}
// update stitched item
stitchingOfflineItem.setIsQa(true);
stitchingOfflineItem.setIsQa( true);
// if FI is already created
} else {
// create OUT from stitching account Finished Item
InventoryTransactionLeg lastInvTransaction = lastFinishedItemInTransactionMap.getOrDefault( preCreatedItem.getId(), null);
if ( lastInvTransaction != null ) {
InventoryTransactionLeg lastInvTransaction = lastFinishedItemInTransactionMap.getOrDefault( preCreatedItem.getId( ), null);
if ( lastInvTransaction != null ) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, stitchingOfflineItem, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.FINISHED_ITEM.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, stitchingOfflineItem, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
}
// create IN in finishing Account Finished Item
finishedItems.add( preCreatedItem );
finishedItems.add( preCreatedItem );
}
}
}
for (FinishedItem finishedItem : finishedItems) {
for ( FinishedItem finishedItem : finishedItems) {
// IN
createInventoryTransactionLeg(transaction, finishedItem, wrapper.getFinishedAccountId(), InventoryTransactionLeg.Type.IN.name(), InventoryArtifactType.FINISHED_ITEM.name());
createInventoryTransactionLeg( transaction, finishedItem, wrapper.getFinishedAccountId( ), InventoryTransactionLeg.Type.IN.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
}
// save updated stitched items
stitchingOfflineItemDAO.saveAll(wrapper.getItems());
stitchingOfflineItemDAO.saveAll( wrapper.getItems( ));
}
}
@ -484,39 +503,39 @@ public class InventoryService {
/*
* segregate finish items
* */
@Transactional(rollbackFor = Exception.class)
public void segregateFinishedItems(FinishedItemWrapper wrapper) {
if (wrapper != null && wrapper.getItems() != null) {
@Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void segregateFinishedItems( FinishedItemWrapper wrapper) {
if ( wrapper != null && wrapper.getItems( ) != null) {
List<FinishedItem> items = wrapper.getItems();
List<FinishedItem> updatedItems = new ArrayList<>();
List<FinishedItem> items = wrapper.getItems( );
List<FinishedItem> updatedItems = new ArrayList<>( );
// finished ids
List<Long> finishedItemIds = items.stream().map(FinishedItem::getId)
.collect(Collectors.toList());
List<Long> finishedItemIds = items.stream( ).map( FinishedItem::getId)
.collect( Collectors.toList( ));
// stitched ids
List<Long> stitchedItemIds = items.stream().map(FinishedItem::getStitchedItemId)
.collect(Collectors.toList());
List<Long> stitchedItemIds = items.stream( ).map( FinishedItem::getStitchedItemId)
.collect( Collectors.toList( ));
// create parent doc type last IN transaction map
Map<Long, InventoryTransactionLeg> lastFinishedItemIdInTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.IN.name(), finishedItemIds, InventoryArtifactType.FINISHED_ITEM.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.IN.name( ), finishedItemIds, InventoryArtifactType.FINISHED_ITEM.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// create parent doc type last OUT transaction map
Map<Long, InventoryTransactionLeg> lastStitchedItemOutTransactionMap = inventoryTransactionLegDAO
.findLastTransactionByParentIdAndParentType(InventoryTransactionLeg.Type.OUT.name(), stitchedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name())
.stream()
.collect(Collectors.toMap(InventoryTransactionLeg::getParentDocumentId, Function.identity()));
.findLastTransactionByParentIdAndParentType( InventoryTransactionLeg.Type.OUT.name( ), stitchedItemIds, InventoryArtifactType.STITCHING_OFFLINE.name( ))
.stream( )
.collect( Collectors.toMap( InventoryTransactionLeg::getParentDocumentId, Function.identity( )));
// create transaction
InventoryTransaction transaction = createInventoryTransaction("Against Segregation of Finished Items");
InventoryTransaction transaction = createInventoryTransaction( "Against Segregation of Finished Items");
// create IN and OUT for all approved items
for (FinishedItem finishedItem : items) {
InventoryTransactionLeg lastInvTransaction = lastFinishedItemIdInTransactionMap.getOrDefault(finishedItem.getId(), null);
finishedItem.setIsQa(true);
for ( FinishedItem finishedItem : items) {
InventoryTransactionLeg lastInvTransaction = lastFinishedItemIdInTransactionMap.getOrDefault( finishedItem.getId( ), null);
finishedItem.setIsQa( true);
/*
* item is not approved and washed is selected then item remain in Finishing account
* */
@ -524,37 +543,37 @@ public class InventoryService {
/*
* item is approved and alter is selected then finished item will to stitching account
* */
if (finishedItem.getQaStatus().equalsIgnoreCase("ALTER")) {
if ( finishedItem.getQaStatus( ).equalsIgnoreCase( "ALTER")) {
// create OUT and IN transactions for FI
if (lastInvTransaction != null) {
if ( lastInvTransaction != null) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.FINISHED_ITEM.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
// IN
// get the stitching account id
long stitchedItemId = finishedItem.getStitchedItemId();
InventoryTransactionLeg lastOutTransaction = lastStitchedItemOutTransactionMap.getOrDefault(stitchedItemId, null);
createInventoryTransactionLeg(transaction, finishedItem, lastOutTransaction.getAccountId(), InventoryTransactionLeg.Type.IN.name(), InventoryArtifactType.FINISHED_ITEM.name());
long stitchedItemId = finishedItem.getStitchedItemId( );
InventoryTransactionLeg lastOutTransaction = lastStitchedItemOutTransactionMap.getOrDefault( stitchedItemId, null);
createInventoryTransactionLeg( transaction, finishedItem, lastOutTransaction.getAccountId( ), InventoryTransactionLeg.Type.IN.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
}
}
/*
* item is approved and grade is selected then fI is move to grade account
*/
if (finishedItem.getQaStatus().equalsIgnoreCase("APPROVED") && finishedItem.getAccountId() != 0) {
if ( finishedItem.getQaStatus( ).equalsIgnoreCase( "APPROVED") && finishedItem.getAccountId( ) != 0) {
// create OUT and IN transactions for FI
if (lastInvTransaction != null) {
if ( lastInvTransaction != null) {
// OUT
long fromAccount = lastInvTransaction.getAccountId();
createInventoryTransactionLeg(transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name(), InventoryArtifactType.FINISHED_ITEM.name());
long fromAccount = lastInvTransaction.getAccountId( );
createInventoryTransactionLeg( transaction, finishedItem, fromAccount, InventoryTransactionLeg.Type.OUT.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
// IN
createInventoryTransactionLeg(transaction, finishedItem, finishedItem.getAccountId(), InventoryTransactionLeg.Type.IN.name(), InventoryArtifactType.FINISHED_ITEM.name());
createInventoryTransactionLeg( transaction, finishedItem, finishedItem.getAccountId( ), InventoryTransactionLeg.Type.IN.name( ), InventoryArtifactType.FINISHED_ITEM.name( ));
}
finishedItem.setIsSegregated(true);
finishedItem.setIsSegregated( true);
}
updatedItems.add(finishedItem);
updatedItems.add( finishedItem);
}
finishedItemDAO.saveAll(updatedItems);
finishedItemDAO.saveAll( updatedItems);
// save finish items
}
}
@ -562,7 +581,7 @@ public class InventoryService {
/*
* find item summary by account
* */
public List<InventorySummary> findItemSummaryByAccountId(long accountId) {
return inventoryTransactionLegDAO.findSummaryByAccountId(accountId);
public List<InventorySummary> findItemSummaryByAccountId( long accountId) {
return inventoryTransactionLegDAO.findSummaryByAccountId( accountId);
}
}

View File

@ -1,17 +1,12 @@
package com.utopiaindustries.service;
import com.utopiaindustries.dao.ctp.CutPieceDAO;
import com.utopiaindustries.dao.ctp.CutPieceTypeDAO;
import com.utopiaindustries.dao.ctp.JobCardDAO;
import com.utopiaindustries.dao.ctp.JobCardItemDAO;
import com.utopiaindustries.dao.ctp.*;
import com.utopiaindustries.dao.uind.ItemDAO;
import com.utopiaindustries.dao.uind.LocationSiteDAO;
import com.utopiaindustries.dao.uind.PurchaseOrderDAO;
import com.utopiaindustries.model.ctp.CutPiece;
import com.utopiaindustries.model.ctp.CutPieceType;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.model.ctp.JobCardItem;
import com.utopiaindustries.model.ctp.*;
import com.utopiaindustries.model.uind.Item;
import com.utopiaindustries.querybuilder.ctp.JobCardQueryBuilder;
import com.utopiaindustries.util.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@ -35,8 +30,9 @@ public class JobCardService {
private final ItemDAO itemDAO;
private final LocationSiteDAO locationSiteDAO;
private final PurchaseOrderDAO purchaseOrderDAO;
private final UserInventoryAccountDAO userInventoryAccountDAO;
public JobCardService(JobCardDAO jobCardDAO, CutPieceTypeDAO cutPieceTypeDAO, JobCardItemDAO jobCardItemDAO, CutPieceDAO cutPieceDAO, ItemDAO itemDAO, LocationSiteDAO locationSiteDAO, PurchaseOrderDAO purchaseOrderDAO) {
public JobCardService(JobCardDAO jobCardDAO, CutPieceTypeDAO cutPieceTypeDAO, JobCardItemDAO jobCardItemDAO, CutPieceDAO cutPieceDAO, ItemDAO itemDAO, LocationSiteDAO locationSiteDAO, PurchaseOrderDAO purchaseOrderDAO, UserInventoryAccountDAO userInventoryAccountDAO) {
this.jobCardDAO = jobCardDAO;
this.cutPieceTypeDAO = cutPieceTypeDAO;
this.jobCardItemDAO = jobCardItemDAO;
@ -44,6 +40,7 @@ public class JobCardService {
this.itemDAO = itemDAO;
this.locationSiteDAO = locationSiteDAO;
this.purchaseOrderDAO = purchaseOrderDAO;
this.userInventoryAccountDAO = userInventoryAccountDAO;
}
/*
@ -66,8 +63,30 @@ public class JobCardService {
/*
* get cards
* */
public List<JobCard> getCards() {
return jobCardDAO.findAll();
public List<JobCard> getCards( String id,
String code,
String status,
String inventoryStatus,
String customer,
String lotNumber,
String purchaseOrderId,
String locationSiteId,
String createdStartDate,
String createdEndDate,
Long limit) {
List<JobCard> jobCards = new ArrayList<>();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if( limit == null ){
limit = 100L;
}
if( StringUtils.isAnyNotNullOrEmpty( id, code, status, inventoryStatus, customer, lotNumber, purchaseOrderId, locationSiteId, createdStartDate, createdEndDate ) ){
String query = JobCardQueryBuilder.buildQuery( id, code, authentication.getName(), status, inventoryStatus, customer, lotNumber, purchaseOrderId, locationSiteId, createdStartDate, createdEndDate, limit );
System.out.println( query );
jobCards = jobCardDAO.findByQuery( query );
} else {
jobCards = jobCardDAO.findByUserAndLimit( authentication.getName(), limit );
}
return jobCards;
}
/*
@ -130,6 +149,58 @@ public class JobCardService {
* find card recursively
* */
public JobCard findCardRecursively(long id) {
// get username
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JobCard jobCard = jobCardDAO.find(id);
// set po and site titles
jobCard.setPurchaseOrderTitle( purchaseOrderDAO.find( jobCard.getPurchaseOrderId() ).getCode() );
jobCard.setLocationTitle( locationSiteDAO.find( jobCard.getLocationSiteId() ).getTitle() );
// fetch only those items which has account id assign to user
List<Long> accountIds = userInventoryAccountDAO.findByUsername( authentication.getName() )
.stream()
.map( UserInventoryAccount::getAccountId )
.collect( Collectors.toList() );
// get items has account ids and has actual production not filled
List<JobCardItem> items = jobCardItemDAO.findByJobCardAndAccountIdsAndIsReceived( id, 0L ,accountIds );
if (items != null && !items.isEmpty()) {
// get job card ite ids
List<Long> jobCardItemIds = items.stream()
.map(JobCardItem::getId)
.collect(Collectors.toList());
// item Ids
List<Long> invItemIds = items.stream()
.map(JobCardItem::getItemId)
.collect(Collectors.toList());
Map<Long, List<CutPiece>> piecesMap = cutPieceDAO.findByJobCardItemIds( jobCardItemIds )
.stream()
.collect(Collectors.groupingBy( CutPiece::getJobCardItemId ));
Map<Long, Item> itemMap = itemDAO.findByIds(invItemIds)
.stream()
.collect(Collectors.toMap(Item::getId, Function.identity()));
for (JobCardItem item : items) {
item.setCutPieces(piecesMap.getOrDefault(item.getId(), new ArrayList<>()));
item.setTitle(itemMap.getOrDefault(item.getItemId(), new Item()).getTitle());
}
}
jobCard.setItems(items);
return jobCard;
}
/*
* find card recursively
* */
public JobCard findCardRecursivelyForView(long id) {
// get username
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JobCard jobCard = jobCardDAO.find(id);
// set po and site titles
jobCard.setPurchaseOrderTitle( purchaseOrderDAO.find( jobCard.getPurchaseOrderId() ).getCode() );
@ -162,7 +233,6 @@ public class JobCardService {
}
jobCard.setItems(items);
return jobCard;
}

View File

@ -76,7 +76,7 @@ public class UserService {
private void createUser( User user ){
User newUser = new User();
newUser.setPassword( bCryptPasswordEncoder.encode( user.getPassword() ) );
newUser.setPassword( user.getPassword() );
if( ! StringUtils.isNullOrEmpty( user.getNewPassword() )){
newUser.setPassword( bCryptPasswordEncoder.encode( user.getNewPassword() ) );
}

View File

@ -1,19 +1,41 @@
(async function () {
Vue.prototype.$accounts = window.ctp.accounts;
Vue.prototype.$types = window.ctp.types;
Vue.component('item-table', {
Vue.component('job-card-items', {
props: ['items'],
methods: {
removeItem: function (index) {
}
},
template: `
<!-- <item-rows v-for="(item,index) in items"-->
<!-- v-bind:key="index"-->
<!-- v-bind:index="index"-->
<!-- v-bind:item="item"-->
<!-- v-on:remove-item="removeItem"> -->
<!-- </item-rows>-->
`,
});
Vue.component('job-card-item', {
props: ['index', 'item', 'items'],
methods: {
removeItem: function (e) {
if (confirm('Do want to delete Item?')) {
if (this.items[index].id === 0) {
this.items.splice(index, 1);
if (this.items[this.index].id === 0) {
this.items.splice(this.index, 1);
} else {
// post request and reload page on success
$.ajax({
url: '/ctp/rest/job-cards?job-card-item-id=' + this.items[index].id,
url: '/ctp/rest/job-cards?job-card-item-id=' + this.items[this.index].id,
method: 'POST',
contentType: 'application/json',
dataType: 'json',
@ -27,40 +49,6 @@
});
}
}
}
},
template: `
<table class="table table-bordered bg-white">
<thead>
<tr>
<th>Item</th>
<th>Item Sku/Title</th>
<th>Cut Panels</th>
<th>Expected Production</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<item-rows v-for="(item,index) in items"
v-bind:key="index"
v-bind:index="index"
v-bind:item="item"
v-on:remove-item="removeItem">
</item-rows>
</tbody>
</table>
`,
});
Vue.component('item-rows', {
props: ['index', 'item'],
methods: {
removeItem: function (e) {
e.preventDefault();
this.$emit('remove-item', this.index);
},
addPieces: function (e) {
e.preventDefault();
@ -99,41 +87,83 @@
}
},
template: `
<tr>
<td width="400">
<div class="form-row position-relative border-bottom my-4">
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id">
<input hidden="hidden" v-bind:name="'items[' + index + '].sku'" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
v-bind:title="item.title"
v-on:item-select="onItemSelect"
v-bind:show-label="false"
v-bind:requuired="true"></item-search>
</td>
<td width="400">
<span class="form-control" readonly >{{item.sku}}</span>
</td>
<td width="500">
<span class="bi-plus-circle-fill" title="Add Pieces" v-on:click="addPieces"></span>
<cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex"
v-bind:pIndex="index"
v-bind:piece="piece"
v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece">
</cut-piece>
</td>
<td width="200">
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-model="item.expectedProductionQuantity" required>
</td>
<td>
<button class="btn btn-sm btn-light" title="Edit" v-on:click="removeItem">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
<input hidden="hidden" v-bind:name="'items[' + index + '].actualProduction'" v-bind:value="item.actualProduction">
<div class="col-sm-3 form-group">
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
v-bind:title="item.title"
v-on:item-select="onItemSelect"
v-bind:show-label="true"
v-bind:requuired="true">
</item-search>
</div>
<div class="col-sm-3 form-group">
<label>Sku</label>
<span class="form-control" readonly >{{item.sku}}</span>
</div>
<div class="col-sm-2 form-group">
<label>Expected Quantity</label>
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProduction'" v-model="item.expectedProduction" required>
</div>
<div class="col-sm-1 form-group">
<label>Length</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].length'" v-model="item.length" required>
</div>
<div class="col-sm-1 form-group">
<label>Width</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].width'" v-model="item.width" required>
</div>
<div class="col-sm-1 form-group">
<label>GSM</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].gsm'" v-model="item.gsm" required>
</div>
<div class="col-sm-1 form-group">
<label>WT./Ply</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].wtPly'" v-model="item.wtPly" required>
</div>
<div class="col-sm-1 form-group">
<label>Number of Ply</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].ply'" v-model="item.ply" required>
</div>
<div class="col-sm-3 form-group">
<label>Cutting Account</label>
<select class="form-control" v-bind:name="'items[' + index + '].accountId'" v-model="item.accountId" required >
<option>Please Select</option>
<option v-for="(account, index) in $accounts"
v-bind:value="account.id"
v-bind:selected="account.id == item.accountId">{{account.title}}</option>
</select>
</div>
<div class="col-sm-1">
<label class="d-block">&nbsp;</label>
<a href="#" title="Remove" class="btn btn-light text-left" v-on:click="removeItem" >
<i class="bi bi-trash"></i>
</a>
</div>
<div class="col-sm-12">
<div class="col-sm-4 border bg-white form-group p-3">
<h6 class="mb-3">Cut Panels</h6>
<cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex"
v-bind:pIndex="index"
v-bind:piece="piece"
v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece">
</cut-piece>
<label class="d-block">&nbsp;</label>
<a href="#" title="Add Cut Panels" class="btn btn-light text-left" v-on:click="addPieces" >
<i class="bi-plus-circle-fill"></i>
</a>
</div>
</div>
</div>
`
});
@ -186,7 +216,14 @@
'jobCardId': 0,
'itemId': 0,
'sku': '',
'expectedProductionQuantity': 0.0,
'expectedProduction': 0.0,
'actualProduction' : 0.0,
'length' : '',
'width' : '',
'gsm' : '',
'wtPly' : '',
'ply' : '',
'accountId' : 0,
cutPieces: []
}
},

View File

@ -1,14 +1,20 @@
( async function(){
Vue.prototype.$types = window.ctp.types;
Vue.prototype.$accounts = window.ctp.accounts;
Vue.component('item-rows', {
props: ['index', 'item'],
methods : {
populateCuttingAccount : function (){
return this.$accounts.find(account => account.id === this.item.accountId).title;
},
},
template: `
<tr>
<td width="400">
<input hidden="hidden" v-bind:value="item.id">
<input hidden="hidden" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardId'" v-bind:value="item.jobCardId" >
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardItemId'" v-bind:value="item.id" >
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
@ -28,15 +34,20 @@
</cut-piece>
</td>
<td width="200">
<span class="form-control" readonly>{{item.expectedProductionQuantity}}</span>
<span class="form-control" readonly>{{item.expectedProduction}}</span>
</td>
<td width="200">
<input class="form-control" type="number" v-bind:name="'items[' + index + '].actualProduction'" v-bind:max="item.expectedProduction" required>
</td>
<td>
<span class="form-control" >{{ populateCuttingAccount() }}</span>
</td>
</tr>
`
});
Vue.component('cut-piece', {
Vue.component ('cut-piece', {
props: ['index', 'piece', 'pIndex'],
methods: {
removePiece: function (e) {
@ -46,34 +57,39 @@
},
template: `
<div class="row mt-1">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].id'" v-bind:value="piece.id">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].jobCardItemId'" v-bind:value="piece.jobCardItemId">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].id'" v-bind:value="piece.id">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].jobCardItemId'" v-bind:value="piece.jobCardItemId">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].type'" v-bind:value="piece.type">
<div class="col-md-5">
<select class="form-control" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].type'" v-model="piece.type" disabled>
<select class="form-control" v-bind:name="'pieces[' + index +'].type'" v-model="piece.type" disabled>
<option value="">Please Select</option>
<option v-for="(type,index) in $types"
v-bind:selected="type.title === piece.type"
v-bind:value="type.title">{{type.title}}</option>
v-bind:value="type.title">{{type.title}}</option>
</select>
</div>
<div class="col-md-5">
<span class="form-control" readonly="">{{piece.quantity}}</span>
<input class="form-control" type="number" v-bind:name="'items[' + pIndex + '].pieces[' + index +'].quantity'" v-model="piece.quantity" required/>
</div>
</div>
`
});
Vue.component('job-card-details',{
props:[ 'jobCard' ],
methods : {
},
template : `
<table class="table table-bordered bg-white col-sm-8">
<table class="table table-bordered bg-white col-sm-12">
<thead>
<tr>
<th>Item</th>
<th>Item Sku/Title</th>
<th>Cut Pieces</th>
<th>Expected Production</th>
<th>Actual Production</th>
<th>Account</th>
</tr>
</thead>
<tbody>

View File

@ -28,32 +28,32 @@
<img th:src="@{/img/utopia-industries-white.svg}" class="page-header__logo" alt="Utopia Industries">
</a>
<ul class="navbar-nav">
<li class="nav-item">
<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>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_CUTTING', 'ROLE_ADMIN')">
<a th:href="@{/cutting/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/cutting') ? 'active' : ''}">Cutting</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_STITCHING', 'ROLE_ADMIN')">
<a th:href="@{/stitching/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/stitching') ? 'active' : ''}">Stitching</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_QUALITY_CONTROL', 'ROLE_ADMIN')">
<a th:href="@{/quality-control/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/quality-control') ? 'active' : ''}">Quality Control</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_FINISHING', 'ROLE_ADMIN')">
<a th:href="@{/finishing/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/finishing') ? 'active' : ''}">Finishing</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_PACKAGING', 'ROLE_ADMIN')">
<a th:href="@{/packaging/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/packaging') ? 'active' : ''}">Packaging</a>
</li>
<li class="nav-item dropdown">
<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">
<!-- Add Inventory Accounts-->

View File

@ -59,8 +59,13 @@
</div>
<div class="bg-light p-3 mb-3">
<h6 class="mb-3">Items</h6>
<item-table v-bind:items.sync="items">
</item-table>
<job-card-item
v-for="(item,index) in items"
v-bind:item="item"
v-bind:key="index"
v-bind:index="index"
v-bind:items.sync="items">
</job-card-item>
<div class="alert alert-danger" v-if="hasDuplicates()"><b>Duplicate Items Selected</b></div>
<button class="btn btn-secondary btn-sm" v-on:click="addItem">
Add Item
@ -75,6 +80,7 @@
<script th:inline="javascript">
window.ctp.jobCard = [[${jobCard}]];
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

@ -8,78 +8,63 @@
<form th:action="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}">
<h5 class="mb-4">Refine Your Search</h5>
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="item-title" maxlength="100" th:value="${param['item-title']}">
<label>ID</label>
<input type="text" class="form-control" name="id" maxlength="100" th:value="${param['id']}">
</div>
<div class="form-group">
<label>Sku</label>
<input type="text" class="form-control" name="item-sku" maxlength="100" th:value="${param['item-sku']}">
</div>
<div class="form-group">
<label>Item Unit</label>
<select class="form-control" name="item-unit" th:value="${param['item-unit']}">
<option value="">Please Select</option>
<option th:each="itemUnit: ${itemUnits}"
th:value="${itemUnit.id}"
th:text="${itemUnit.title}"
th:selected="${#strings.equals(param['item-unit'], #strings.toString(itemUnit.id))}"></option>
</select>
</div>
<div class="form-group" th:if="${isShown}">
<label>Item Status</label>
<select class="form-control" name="item-request-approval-status" data-s2 multiple>
<option value="ALL" th:selected="${param['item-request-approval-status'] == null || #strings.equals('ALL', param['item-request-approval-status'])}">ALL</option>
<option th:each="status: ${T(com.utopiaindustries.uind.model.inventory.ItemRequestApprovalStatus).values()}"
th:value="${status}"
th:text="${status}"
th:selected="${param['item-request-approval-status'] == null ? false : #lists.contains(param['item-request-approval-status'], #strings.toString(status))}"></option>
</select>
</div>
<div data-item-type-category-container>
<div class="form-group">
<label>Type</label>
<select name="item-type-id" class="form-control" data-item-type>
<option data-empty-option value="">Please select</option>
</select>
</div>
<div class="form-group">
<label>Category</label>
<select name="item-category-id" class="form-control" data-item-category id = "item-category-select">
<option data-empty-option value="">Please select</option>
</select>
</div>
</div>
<!-- th:if="${isRequest}"-->
<div class="form-group">
<label>From Date</label>
<input type="date" class="form-control" name="from-date" >
</div>
<div class="form-group">
<label>To Date</label>
<input type="date" class="form-control" name="to-date" >
<label>Code</label>
<input type="text" class="form-control" name="code" maxlength="100" th:value="${param['code']}">
</div>
<div class="form-group">
<label>Status</label>
<select name="item-status" class="form-control">
<option value="">All</option>
<option value="1" th:selected="${#strings.equals(param['item-status'], #strings.toString(1))}">Active</option>
<option value="0" th:selected="${#strings.equals(param['item-status'], #strings.toString(0))}">Inactive</option>
<select class="form-control" name="status">
<option value="">Please Select</option>
<option th:each="status: ${statuses}"
th:value="${status}"
th:text="${status}"
th:selected="${param['status'] == null ? false : #strings.equals(param['status'], status) }"></option>
</select>
</div>
<!-- number of items -->
<div class="form-group">
<label>Number of Items</label>
<input type="number" class="form-control" name="item-count" th:value="(${param['item-count']} != null) ? ${param['item-count']} : 100">
<label>Inventory Status</label>
<select class="form-control" name="inventory-status">
<option value="">Please Select</option>
<option th:each="status: ${invStatuses}"
th:value="${status}"
th:text="${status}"
th:selected="${param['inventory-status'] == null ? false : #strings.equals(param['inventory-status'], status) }"></option>
</select>
</div>
<div class="form-group">
<label>Customer</label>
<input type="text" class="form-control" name="customer" maxlength="100" th:value="${param['customer']}">
</div>
<div class="form-group">
<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']}">
<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">
<label>From Date</label>
<input type="date" class="form-control" name="created-start-date" th:value="${param['created-start-date']}" >
</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']}" >
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="limit"
th:value="(${param['limit']} != null) ? ${param['limit']} : 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>
<button th:if="${isRequest}"
sec:authorize="hasAnyRole('ROLE_UIM_ITEM_APPROVE_DEPT', 'ROLE_UIM_ITEM_APPROVE_DIV', 'ROLE_UIM_ITEM_APPROVE_ALL', 'ROLE_ADMIN')"
class="btn btn-primary btn-block mt-2"
type="button"
data-item-mark-approve>
Mark Approve
</button>
<a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"
class="btn btn-secondary btn-block">Reset</a>
</form>
</div>
</aside>

View File

@ -26,7 +26,7 @@
</div>
<div class="col-sm-3 form-group">
<label>Password</label>
<input class="form-control" th:field="*{newPassword}" required>
<input class="form-control" th:field="*{newPassword}" th:required="${isNew != null && isNew}">
</div>
<div class="col-sm-3 form-group">
<label for="enable">Enabled</label>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -12,7 +12,8 @@
<h3 class="pb-2">Receive Inventory</h3>
<form th:action="@{/cutting/receive-inventory}"
method="POST"
id="receiveInvApp">
id="receiveInvApp"
th:object="${wrapper}">
<div class="bg-light p-3 mb-3">
<div class="form-row">
<div class="col-sm-3 p-0">
@ -22,16 +23,16 @@
v-bind:required="true"
></job-card-search>
</div>
<div class="col-sm-3">
<label>Cutting Account</label>
<select class="form-control" name="account-id" required>
<option value="">Please Select</option>
<option th:each="account :${accounts}"
th:value="${account.id}"
th:text="${account.title}"
th:title="${account.notes}"></option>
</select>
</div>
<!-- <div class="col-sm-3">-->
<!-- <label>Cutting Account</label>-->
<!-- <select class="form-control" name="account-id" required>-->
<!-- <option value="">Please Select</option>-->
<!-- <option th:each="account :${accounts}"-->
<!-- th:value="${account.id}"-->
<!-- th:text="${account.title}"-->
<!-- th:title="${account.notes}"></option>-->
<!-- </select>-->
<!-- </div>-->
</div>
</div>
<div class="bg-light p-3 mb-3" v-if="jobCard.id !== undefined">
@ -47,7 +48,7 @@
</thead>
<tbody>
<tr>
<td>{{jobCard.code}}</td>
<td> {{jobCard.code}}</td>
<td>{{jobCard.jobOrderId}}</td>
<td>
<span class="badge" v-bind:class="getStatus" v-if="jobCard.status" >{{jobCard.status}}</span>
@ -69,6 +70,7 @@
</form>
<script th:inline="javascript">
window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
</script>
<script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/receive-inventory.js}"></script>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="_fragments :: head(${error})"></head>
<body>
<div class="container-fluid">
<header class="row page-header" th:replace="_fragments :: page-header"></header>
<main class="row page-main">
<div class="col-sm">
<div class="d-flex justify-content-center align-items-center">
<div class="pt-5 mt-5">
<h1 class="font-weight-bold mb-3 text-danger">403 - Access Denied</h1>
<h4 class="mb-3">You are not authorized to view this page.</h4>
<h4>Please contact concerned department for granting you required rights.</h4>
</div>
</div>
</div>
</main>
</div>
<div th:replace="_fragments :: page-footer-scripts"></div>
</body>
</html>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -23,6 +23,10 @@
<th>Job Order</th>
<th>Status</th>
<th>Inventory Status</th>
<th>Customer</th>
<th>Lot Number</th>
<th>Purchase Order ID</th>
<th>Location Site</th>
<th>Added Date</th>
<th>Added By</th>
<th>Actions</th>
@ -40,6 +44,14 @@
<span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span>
<span th:unless="*{inventoryStatus}">-</span>
</td>
<td th:text="*{customer}"></td>
<td th:text="*{lotNumber}"></td>
<td th:text="*{purchaseOrderId}"></td>
<td>
<th:block th:switch="*{locationSiteId}">
<span th:each="location: ${locations}" th:case="${location.id}" th:text="${location.title}"></span>
</th:block>
</td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td th:text="*{createdBy}"></td>
<td>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -21,7 +21,7 @@
></stitching-offline-item>
</div>
<div class="col-sm-3 form-group">
<label>Packaging Account</label>
<label>Finishing Account</label>
<select class="form-control" name="account-id" th:field="*{finishedAccountId}" required>
<option value="">PLease select</option>
<option th:each="account : ${accounts}"

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -38,18 +38,26 @@
</div>
<div class="bg-light p-3 mb-3 col-sm-8">
<h6>Items</h6>
<div class="form-row col-sm-10">
<div class="form-row col-sm-12">
<table class="table mt-2 table-bordered table-hover bg-white">
<tr>
<th></th>
<th>ID</th>
<th>Item ID</th>
<th>Sku</th>
<th>Expected Production</th>
<th>Actual Production</th>
<th>Current Production</th>
<th>Production</th>
</tr>
<tbody>
<tr 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>
</div>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id">
<span class="form-control">{{item.id}}</span>
@ -63,8 +71,12 @@
<span class="form-control">{{item.sku}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-bind:value="item.expectedProductionQuantity">
<span class="form-control">{{item.expectedProductionQuantity}}</span>
<input hidden="hidden" v-bind:name="'items[' + index + '].expectedProduction'" v-bind:value="item.expectedProduction">
<span class="form-control">{{item.expectedProduction}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].actualProduction'" v-bind:value="item.actualProduction">
<span class="form-control">{{item.actualProduction}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
@ -75,8 +87,9 @@
type="number"
v-bind:value="item.production"
v-bind:min="0"
v-bind:max="item.expectedProductionQuantity - item.totalProduction"
required>
v-bind:max="item.actualProduction - item.totalProduction"
v-bind:readonly="!item.isSelected"
>
</td>
</tr>
</tbody>

View File

@ -1,19 +1,41 @@
(async function () {
Vue.prototype.$accounts = window.ctp.accounts;
Vue.prototype.$types = window.ctp.types;
Vue.component('item-table', {
Vue.component('job-card-items', {
props: ['items'],
methods: {
removeItem: function (index) {
}
},
template: `
<!-- <item-rows v-for="(item,index) in items"-->
<!-- v-bind:key="index"-->
<!-- v-bind:index="index"-->
<!-- v-bind:item="item"-->
<!-- v-on:remove-item="removeItem"> -->
<!-- </item-rows>-->
`,
});
Vue.component('job-card-item', {
props: ['index', 'item', 'items'],
methods: {
removeItem: function (e) {
if (confirm('Do want to delete Item?')) {
if (this.items[index].id === 0) {
this.items.splice(index, 1);
if (this.items[this.index].id === 0) {
this.items.splice(this.index, 1);
} else {
// post request and reload page on success
$.ajax({
url: '/ctp/rest/job-cards?job-card-item-id=' + this.items[index].id,
url: '/ctp/rest/job-cards?job-card-item-id=' + this.items[this.index].id,
method: 'POST',
contentType: 'application/json',
dataType: 'json',
@ -27,40 +49,6 @@
});
}
}
}
},
template: `
<table class="table table-bordered bg-white">
<thead>
<tr>
<th>Item</th>
<th>Item Sku/Title</th>
<th>Cut Panels</th>
<th>Expected Production</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<item-rows v-for="(item,index) in items"
v-bind:key="index"
v-bind:index="index"
v-bind:item="item"
v-on:remove-item="removeItem">
</item-rows>
</tbody>
</table>
`,
});
Vue.component('item-rows', {
props: ['index', 'item'],
methods: {
removeItem: function (e) {
e.preventDefault();
this.$emit('remove-item', this.index);
},
addPieces: function (e) {
e.preventDefault();
@ -99,41 +87,83 @@
}
},
template: `
<tr>
<td width="400">
<div class="form-row position-relative border-bottom my-4">
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id">
<input hidden="hidden" v-bind:name="'items[' + index + '].sku'" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
v-bind:title="item.title"
v-on:item-select="onItemSelect"
v-bind:show-label="false"
v-bind:requuired="true"></item-search>
</td>
<td width="400">
<span class="form-control" readonly >{{item.sku}}</span>
</td>
<td width="500">
<span class="bi-plus-circle-fill" title="Add Pieces" v-on:click="addPieces"></span>
<cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex"
v-bind:pIndex="index"
v-bind:piece="piece"
v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece">
</cut-piece>
</td>
<td width="200">
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-model="item.expectedProductionQuantity" required>
</td>
<td>
<button class="btn btn-sm btn-light" title="Edit" v-on:click="removeItem">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
<input hidden="hidden" v-bind:name="'items[' + index + '].actualProduction'" v-bind:value="item.actualProduction">
<div class="col-sm-3 form-group">
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
v-bind:title="item.title"
v-on:item-select="onItemSelect"
v-bind:show-label="true"
v-bind:requuired="true">
</item-search>
</div>
<div class="col-sm-3 form-group">
<label>Sku</label>
<span class="form-control" readonly >{{item.sku}}</span>
</div>
<div class="col-sm-2 form-group">
<label>Expected Quantity</label>
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProduction'" v-model="item.expectedProduction" required>
</div>
<div class="col-sm-1 form-group">
<label>Length</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].length'" v-model="item.length" required>
</div>
<div class="col-sm-1 form-group">
<label>Width</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].width'" v-model="item.width" required>
</div>
<div class="col-sm-1 form-group">
<label>GSM</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].gsm'" v-model="item.gsm" required>
</div>
<div class="col-sm-1 form-group">
<label>WT./Ply</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].wtPly'" v-model="item.wtPly" required>
</div>
<div class="col-sm-1 form-group">
<label>Number of Ply</label>
<input type="text" class="form-control" v-bind:name="'items[' + index + '].ply'" v-model="item.ply" required>
</div>
<div class="col-sm-3 form-group">
<label>Cutting Account</label>
<select class="form-control" v-bind:name="'items[' + index + '].accountId'" v-model="item.accountId" required >
<option>Please Select</option>
<option v-for="(account, index) in $accounts"
v-bind:value="account.id"
v-bind:selected="account.id == item.accountId">{{account.title}}</option>
</select>
</div>
<div class="col-sm-1">
<label class="d-block">&nbsp;</label>
<a href="#" title="Remove" class="btn btn-light text-left" v-on:click="removeItem" >
<i class="bi bi-trash"></i>
</a>
</div>
<div class="col-sm-12">
<div class="col-sm-4 border bg-white form-group p-3">
<h6 class="mb-3">Cut Panels</h6>
<cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex"
v-bind:pIndex="index"
v-bind:piece="piece"
v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece">
</cut-piece>
<label class="d-block">&nbsp;</label>
<a href="#" title="Add Cut Panels" class="btn btn-light text-left" v-on:click="addPieces" >
<i class="bi-plus-circle-fill"></i>
</a>
</div>
</div>
</div>
`
});
@ -186,7 +216,14 @@
'jobCardId': 0,
'itemId': 0,
'sku': '',
'expectedProductionQuantity': 0.0,
'expectedProduction': 0.0,
'actualProduction' : 0.0,
'length' : '',
'width' : '',
'gsm' : '',
'wtPly' : '',
'ply' : '',
'accountId' : 0,
cutPieces: []
}
},

View File

@ -1,14 +1,20 @@
( async function(){
Vue.prototype.$types = window.ctp.types;
Vue.prototype.$accounts = window.ctp.accounts;
Vue.component('item-rows', {
props: ['index', 'item'],
methods : {
populateCuttingAccount : function (){
return this.$accounts.find(account => account.id === this.item.accountId).title;
},
},
template: `
<tr>
<td width="400">
<input hidden="hidden" v-bind:value="item.id">
<input hidden="hidden" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardId'" v-bind:value="item.jobCardId" >
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardItemId'" v-bind:value="item.id" >
<item-search
v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId"
@ -28,15 +34,20 @@
</cut-piece>
</td>
<td width="200">
<span class="form-control" readonly>{{item.expectedProductionQuantity}}</span>
<span class="form-control" readonly>{{item.expectedProduction}}</span>
</td>
<td width="200">
<input class="form-control" type="number" v-bind:name="'items[' + index + '].actualProduction'" v-bind:max="item.expectedProduction" required>
</td>
<td>
<span class="form-control" >{{ populateCuttingAccount() }}</span>
</td>
</tr>
`
});
Vue.component('cut-piece', {
Vue.component ('cut-piece', {
props: ['index', 'piece', 'pIndex'],
methods: {
removePiece: function (e) {
@ -46,34 +57,39 @@
},
template: `
<div class="row mt-1">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].id'" v-bind:value="piece.id">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].jobCardItemId'" v-bind:value="piece.jobCardItemId">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].id'" v-bind:value="piece.id">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].jobCardItemId'" v-bind:value="piece.jobCardItemId">
<input hidden="hidden" v-bind:name="'items[' + pIndex + '].pieces[' + index + '].type'" v-bind:value="piece.type">
<div class="col-md-5">
<select class="form-control" v-bind:name="'items[' + pIndex + '].cutPieces[' + index +'].type'" v-model="piece.type" disabled>
<select class="form-control" v-bind:name="'pieces[' + index +'].type'" v-model="piece.type" disabled>
<option value="">Please Select</option>
<option v-for="(type,index) in $types"
v-bind:selected="type.title === piece.type"
v-bind:value="type.title">{{type.title}}</option>
v-bind:value="type.title">{{type.title}}</option>
</select>
</div>
<div class="col-md-5">
<span class="form-control" readonly="">{{piece.quantity}}</span>
<input class="form-control" type="number" v-bind:name="'items[' + pIndex + '].pieces[' + index +'].quantity'" v-model="piece.quantity" required/>
</div>
</div>
`
});
Vue.component('job-card-details',{
props:[ 'jobCard' ],
methods : {
},
template : `
<table class="table table-bordered bg-white col-sm-8">
<table class="table table-bordered bg-white col-sm-12">
<thead>
<tr>
<th>Item</th>
<th>Item Sku/Title</th>
<th>Cut Pieces</th>
<th>Expected Production</th>
<th>Actual Production</th>
<th>Account</th>
</tr>
</thead>
<tbody>

View File

@ -28,32 +28,32 @@
<img th:src="@{/img/utopia-industries-white.svg}" class="page-header__logo" alt="Utopia Industries">
</a>
<ul class="navbar-nav">
<li class="nav-item">
<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>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_CUTTING', 'ROLE_ADMIN')">
<a th:href="@{/cutting/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/cutting') ? 'active' : ''}">Cutting</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_STITCHING', 'ROLE_ADMIN')">
<a th:href="@{/stitching/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/stitching') ? 'active' : ''}">Stitching</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_QUALITY_CONTROL', 'ROLE_ADMIN')">
<a th:href="@{/quality-control/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/quality-control') ? 'active' : ''}">Quality Control</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_FINISHING', 'ROLE_ADMIN')">
<a th:href="@{/finishing/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/finishing') ? 'active' : ''}">Finishing</a>
</li>
<li class="nav-item">
<li class="nav-item" sec:authorize="hasAnyRole('ROLE_PACKAGING', 'ROLE_ADMIN')">
<a th:href="@{/packaging/}" class="nav-link"
th:classappend="${#strings.startsWith(#httpServletRequest.getRequestURI(), '/ctp/packaging') ? 'active' : ''}">Packaging</a>
</li>
<li class="nav-item dropdown">
<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">
<!-- Add Inventory Accounts-->

View File

@ -59,8 +59,13 @@
</div>
<div class="bg-light p-3 mb-3">
<h6 class="mb-3">Items</h6>
<item-table v-bind:items.sync="items">
</item-table>
<job-card-item
v-for="(item,index) in items"
v-bind:item="item"
v-bind:key="index"
v-bind:index="index"
v-bind:items.sync="items">
</job-card-item>
<div class="alert alert-danger" v-if="hasDuplicates()"><b>Duplicate Items Selected</b></div>
<button class="btn btn-secondary btn-sm" v-on:click="addItem">
Add Item
@ -75,6 +80,7 @@
<script th:inline="javascript">
window.ctp.jobCard = [[${jobCard}]];
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

@ -8,78 +8,63 @@
<form th:action="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}">
<h5 class="mb-4">Refine Your Search</h5>
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="item-title" maxlength="100" th:value="${param['item-title']}">
<label>ID</label>
<input type="text" class="form-control" name="id" maxlength="100" th:value="${param['id']}">
</div>
<div class="form-group">
<label>Sku</label>
<input type="text" class="form-control" name="item-sku" maxlength="100" th:value="${param['item-sku']}">
</div>
<div class="form-group">
<label>Item Unit</label>
<select class="form-control" name="item-unit" th:value="${param['item-unit']}">
<option value="">Please Select</option>
<option th:each="itemUnit: ${itemUnits}"
th:value="${itemUnit.id}"
th:text="${itemUnit.title}"
th:selected="${#strings.equals(param['item-unit'], #strings.toString(itemUnit.id))}"></option>
</select>
</div>
<div class="form-group" th:if="${isShown}">
<label>Item Status</label>
<select class="form-control" name="item-request-approval-status" data-s2 multiple>
<option value="ALL" th:selected="${param['item-request-approval-status'] == null || #strings.equals('ALL', param['item-request-approval-status'])}">ALL</option>
<option th:each="status: ${T(com.utopiaindustries.uind.model.inventory.ItemRequestApprovalStatus).values()}"
th:value="${status}"
th:text="${status}"
th:selected="${param['item-request-approval-status'] == null ? false : #lists.contains(param['item-request-approval-status'], #strings.toString(status))}"></option>
</select>
</div>
<div data-item-type-category-container>
<div class="form-group">
<label>Type</label>
<select name="item-type-id" class="form-control" data-item-type>
<option data-empty-option value="">Please select</option>
</select>
</div>
<div class="form-group">
<label>Category</label>
<select name="item-category-id" class="form-control" data-item-category id = "item-category-select">
<option data-empty-option value="">Please select</option>
</select>
</div>
</div>
<!-- th:if="${isRequest}"-->
<div class="form-group">
<label>From Date</label>
<input type="date" class="form-control" name="from-date" >
</div>
<div class="form-group">
<label>To Date</label>
<input type="date" class="form-control" name="to-date" >
<label>Code</label>
<input type="text" class="form-control" name="code" maxlength="100" th:value="${param['code']}">
</div>
<div class="form-group">
<label>Status</label>
<select name="item-status" class="form-control">
<option value="">All</option>
<option value="1" th:selected="${#strings.equals(param['item-status'], #strings.toString(1))}">Active</option>
<option value="0" th:selected="${#strings.equals(param['item-status'], #strings.toString(0))}">Inactive</option>
<select class="form-control" name="status">
<option value="">Please Select</option>
<option th:each="status: ${statuses}"
th:value="${status}"
th:text="${status}"
th:selected="${param['status'] == null ? false : #strings.equals(param['status'], status) }"></option>
</select>
</div>
<!-- number of items -->
<div class="form-group">
<label>Number of Items</label>
<input type="number" class="form-control" name="item-count" th:value="(${param['item-count']} != null) ? ${param['item-count']} : 100">
<label>Inventory Status</label>
<select class="form-control" name="inventory-status">
<option value="">Please Select</option>
<option th:each="status: ${invStatuses}"
th:value="${status}"
th:text="${status}"
th:selected="${param['inventory-status'] == null ? false : #strings.equals(param['inventory-status'], status) }"></option>
</select>
</div>
<div class="form-group">
<label>Customer</label>
<input type="text" class="form-control" name="customer" maxlength="100" th:value="${param['customer']}">
</div>
<div class="form-group">
<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']}">
<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">
<label>From Date</label>
<input type="date" class="form-control" name="created-start-date" th:value="${param['created-start-date']}" >
</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']}" >
</div>
<div class="form-group">
<label>Count</label>
<input type="number" class="form-control" name="limit"
th:value="(${param['limit']} != null) ? ${param['limit']} : 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>
<button th:if="${isRequest}"
sec:authorize="hasAnyRole('ROLE_UIM_ITEM_APPROVE_DEPT', 'ROLE_UIM_ITEM_APPROVE_DIV', 'ROLE_UIM_ITEM_APPROVE_ALL', 'ROLE_ADMIN')"
class="btn btn-primary btn-block mt-2"
type="button"
data-item-mark-approve>
Mark Approve
</button>
<a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"
class="btn btn-secondary btn-block">Reset</a>
</form>
</div>
</aside>

View File

@ -26,7 +26,7 @@
</div>
<div class="col-sm-3 form-group">
<label>Password</label>
<input class="form-control" th:field="*{newPassword}" required>
<input class="form-control" th:field="*{newPassword}" th:required="${isNew != null && isNew}">
</div>
<div class="col-sm-3 form-group">
<label for="enable">Enabled</label>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -12,7 +12,8 @@
<h3 class="pb-2">Receive Inventory</h3>
<form th:action="@{/cutting/receive-inventory}"
method="POST"
id="receiveInvApp">
id="receiveInvApp"
th:object="${wrapper}">
<div class="bg-light p-3 mb-3">
<div class="form-row">
<div class="col-sm-3 p-0">
@ -22,16 +23,16 @@
v-bind:required="true"
></job-card-search>
</div>
<div class="col-sm-3">
<label>Cutting Account</label>
<select class="form-control" name="account-id" required>
<option value="">Please Select</option>
<option th:each="account :${accounts}"
th:value="${account.id}"
th:text="${account.title}"
th:title="${account.notes}"></option>
</select>
</div>
<!-- <div class="col-sm-3">-->
<!-- <label>Cutting Account</label>-->
<!-- <select class="form-control" name="account-id" required>-->
<!-- <option value="">Please Select</option>-->
<!-- <option th:each="account :${accounts}"-->
<!-- th:value="${account.id}"-->
<!-- th:text="${account.title}"-->
<!-- th:title="${account.notes}"></option>-->
<!-- </select>-->
<!-- </div>-->
</div>
</div>
<div class="bg-light p-3 mb-3" v-if="jobCard.id !== undefined">
@ -47,7 +48,7 @@
</thead>
<tbody>
<tr>
<td>{{jobCard.code}}</td>
<td> {{jobCard.code}}</td>
<td>{{jobCard.jobOrderId}}</td>
<td>
<span class="badge" v-bind:class="getStatus" v-if="jobCard.status" >{{jobCard.status}}</span>
@ -69,6 +70,7 @@
</form>
<script th:inline="javascript">
window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
</script>
<script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/receive-inventory.js}"></script>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -23,6 +23,10 @@
<th>Job Order</th>
<th>Status</th>
<th>Inventory Status</th>
<th>Customer</th>
<th>Lot Number</th>
<th>Purchase Order ID</th>
<th>Location Site</th>
<th>Added Date</th>
<th>Added By</th>
<th>Actions</th>
@ -40,6 +44,14 @@
<span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span>
<span th:unless="*{inventoryStatus}">-</span>
</td>
<td th:text="*{customer}"></td>
<td th:text="*{lotNumber}"></td>
<td th:text="*{purchaseOrderId}"></td>
<td>
<th:block th:switch="*{locationSiteId}">
<span th:each="location: ${locations}" th:case="${location.id}" th:text="${location.title}"></span>
</th:block>
</td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td th:text="*{createdBy}"></td>
<td>

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -21,7 +21,7 @@
></stitching-offline-item>
</div>
<div class="col-sm-3 form-group">
<label>Packaging Account</label>
<label>Finishing Account</label>
<select class="form-control" name="account-id" th:field="*{finishedAccountId}" required>
<option value="">PLease select</option>
<option th:each="account : ${accounts}"

View File

@ -44,7 +44,10 @@
<td th:text="*{id}"></td>
<td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></td>
<td th:text="*{active}"></td>
<td>
<span class="badge badge-ACTIVE" th:if="*{active}">ACTIVE</span>
<span class="badge badge-danger" th:unless="*{active}" >INACTIVE</span>
</td>
<td th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td>
<td >
@ -96,7 +99,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`,
url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();
@ -119,7 +122,7 @@
else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`,
url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){
// show fetched page
$row.child( data ).show();

View File

@ -38,18 +38,26 @@
</div>
<div class="bg-light p-3 mb-3 col-sm-8">
<h6>Items</h6>
<div class="form-row col-sm-10">
<div class="form-row col-sm-12">
<table class="table mt-2 table-bordered table-hover bg-white">
<tr>
<th></th>
<th>ID</th>
<th>Item ID</th>
<th>Sku</th>
<th>Expected Production</th>
<th>Actual Production</th>
<th>Current Production</th>
<th>Production</th>
</tr>
<tbody>
<tr 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>
</div>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id">
<span class="form-control">{{item.id}}</span>
@ -63,8 +71,12 @@
<span class="form-control">{{item.sku}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-bind:value="item.expectedProductionQuantity">
<span class="form-control">{{item.expectedProductionQuantity}}</span>
<input hidden="hidden" v-bind:name="'items[' + index + '].expectedProduction'" v-bind:value="item.expectedProduction">
<span class="form-control">{{item.expectedProduction}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].actualProduction'" v-bind:value="item.actualProduction">
<span class="form-control">{{item.actualProduction}}</span>
</td>
<td>
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction">
@ -75,8 +87,9 @@
type="number"
v-bind:value="item.production"
v-bind:min="0"
v-bind:max="item.expectedProductionQuantity - item.totalProduction"
required>
v-bind:max="item.actualProduction - item.totalProduction"
v-bind:readonly="!item.isSelected"
>
</td>
</tr>
</tbody>