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

View File

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

View File

@ -1,5 +1,6 @@
package com.utopiaindustries.controller; package com.utopiaindustries.controller;
import com.utopiaindustries.auth.AdminRole;
import com.utopiaindustries.model.ctp.InventoryAccount; import com.utopiaindustries.model.ctp.InventoryAccount;
import com.utopiaindustries.service.InventoryAccountService; import com.utopiaindustries.service.InventoryAccountService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@ -8,6 +9,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller @Controller
@AdminRole
@RequestMapping( "/inventory-accounts" ) @RequestMapping( "/inventory-accounts" )
public class InventoryAccountController { 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; package com.utopiaindustries.controller;
import com.utopiaindustries.auth.JobCardRole;
import com.utopiaindustries.model.ctp.JobCard; import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.service.InventoryAccountService;
import com.utopiaindustries.service.JobCardService; import com.utopiaindustries.service.JobCardService;
import com.utopiaindustries.service.LocationService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller @Controller
@JobCardRole
@RequestMapping( "/job-cards" ) @RequestMapping( "/job-cards" )
public class JobCardController { public class JobCardController {
private final JobCardService jobCardService; 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.jobCardService = jobCardService;
this.locationService = locationService;
this.inventoryAccountService = inventoryAccountService;
} }
/** /**
* get all job cards * get all job cards
* */ * */
@GetMapping @GetMapping
public String showJobCardList( Model model ){ public String showJobCardList( @RequestParam( value = "id", required = false ) String id,
model.addAttribute("cards", jobCardService.getCards() ); @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"; return "job-card-list";
} }
@ -30,14 +55,16 @@ public class JobCardController {
public String showJobCardForm( Model model ){ public String showJobCardForm( Model model ){
model.addAttribute("jobCard", jobCardService.createNewJobCard() ); model.addAttribute("jobCard", jobCardService.createNewJobCard() );
model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() ); model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() );
model.addAttribute("accounts", inventoryAccountService.getAllCuttingAccounts( ) );
return "job-card-add"; return "job-card-add";
} }
@GetMapping( value = "/edit/{id}" ) @GetMapping( value = "/edit/{id}" )
public String showJobCardEditForm( @PathVariable("id") long id, public String showJobCardEditForm( @PathVariable("id") long id,
Model model ){ Model model ){
model.addAttribute("jobCard", jobCardService.findCardRecursively( id ) ); model.addAttribute("jobCard", jobCardService.findCardRecursivelyForView( id ) );
model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() ); model.addAttribute("cutPieceTypes", jobCardService.getAllPieceTypes() );
model.addAttribute("accounts", inventoryAccountService.getAllCuttingAccounts() );
return "job-card-edit"; return "job-card-edit";
} }

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@ public class UserController {
model.addAttribute("user", userService.createEmptyUser() ); model.addAttribute("user", userService.createEmptyUser() );
model.addAttribute("accounts", inventoryAccountService.findInventoryAccounts() ); model.addAttribute("accounts", inventoryAccountService.findInventoryAccounts() );
model.addAttribute("roles", Roles.values() ); model.addAttribute("roles", Roles.values() );
model.addAttribute("isNew", true );
return "_user-fragment"; 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_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_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_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) { public InventoryAccountDAO(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
@ -136,4 +137,11 @@ public class InventoryAccountDAO {
public List<InventoryAccount> findByQuery( String query ){ public List<InventoryAccount> findByQuery( String query ){
return namedParameterJdbcTemplate.query( query, new InventoryAccountRowMapper() ); 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 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_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_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 // prepare query params
@ -98,4 +99,15 @@ public class JobCardDAO {
params.addValue("status", status ); params.addValue("status", status );
return namedParameterJdbcTemplate.query(SELECT_BY_LIKE_CODE_AND_INV_STATUS_AND_STATUS, params, new JobCardRowMapper() ); 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@Repository @Repository
public class JobCardItemDAO { 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 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 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 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) { public JobCardItemDAO(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
@ -34,8 +37,15 @@ public class JobCardItemDAO {
.addValue( "job_card_id", jobCardItem.getJobCardId() ) .addValue( "job_card_id", jobCardItem.getJobCardId() )
.addValue( "item_id", jobCardItem.getItemId() ) .addValue( "item_id", jobCardItem.getItemId() )
.addValue( "sku", jobCardItem.getSku() ) .addValue( "sku", jobCardItem.getSku() )
.addValue( "expected_production_quantity", jobCardItem.getExpectedProductionQuantity() ) .addValue( "expected_production", jobCardItem.getExpectedProduction() )
.addValue("total_production", jobCardItem.getTotalProduction() ); .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; return params;
} }
@ -84,4 +94,19 @@ public class JobCardItemDAO {
params.addValue( "card_id", cardId ); params.addValue( "card_id", cardId );
return namedParameterJdbcTemplate.query(SELECT_BY_CARD_ID, params, new JobCardItemRowMapper() ); 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.setJobCardId( rs.getLong( "job_card_id" ) );
jobCardItem.setItemId( rs.getLong( "item_id" ) ); jobCardItem.setItemId( rs.getLong( "item_id" ) );
jobCardItem.setSku( rs.getString( "sku" ) ); 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.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; return jobCardItem;
} }
} }

View File

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

View File

@ -9,15 +9,24 @@ public class JobCardItem {
private long jobCardId; private long jobCardId;
private long itemId; private long itemId;
private String sku; private String sku;
private BigDecimal expectedProductionQuantity; private BigDecimal expectedProduction;
private BigDecimal actualProduction;
private BigDecimal totalProduction; private BigDecimal totalProduction;
private long accountId;
private BigDecimal production; private BigDecimal production;
private String length;
private String width;
private String gsm;
private String wtPly;
private String ply;
// wrapper // wrapper
private List<CutPiece> cutPieces; private List<CutPiece> cutPieces;
private String title; private String title;
private boolean isSelected;
public JobCardItem() { public JobCardItem() {
this.expectedProductionQuantity = BigDecimal.ZERO; this.expectedProduction = BigDecimal.ZERO;
this.actualProduction = BigDecimal.ZERO;
this.totalProduction = BigDecimal.ZERO; this.totalProduction = BigDecimal.ZERO;
this.production = BigDecimal.ZERO; this.production = BigDecimal.ZERO;
} }
@ -54,12 +63,20 @@ public class JobCardItem {
this.sku = sku; this.sku = sku;
} }
public BigDecimal getExpectedProductionQuantity() { public BigDecimal getExpectedProduction() {
return expectedProductionQuantity; return expectedProduction;
} }
public void setExpectedProductionQuantity(BigDecimal expectedProductionQuantity) { public void setExpectedProduction(BigDecimal expectedProduction) {
this.expectedProductionQuantity = expectedProductionQuantity; this.expectedProduction = expectedProduction;
}
public BigDecimal getActualProduction() {
return actualProduction;
}
public void setActualProduction(BigDecimal actualProduction) {
this.actualProduction = actualProduction;
} }
public List<CutPiece> getCutPieces() { public List<CutPiece> getCutPieces() {
@ -86,6 +103,14 @@ public class JobCardItem {
this.totalProduction = totalProduction; this.totalProduction = totalProduction;
} }
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public BigDecimal getProduction() { public BigDecimal getProduction() {
return production; return production;
} }
@ -94,6 +119,54 @@ public class JobCardItem {
this.production = production; 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 @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@ -114,7 +187,15 @@ public class JobCardItem {
", jobCardId=" + jobCardId + ", jobCardId=" + jobCardId +
", itemId=" + itemId + ", itemId=" + itemId +
", sku='" + sku + '\'' + ", sku='" + sku + '\'' +
", expectedProductionQuantity=" + expectedProductionQuantity + ", expectedProduction=" + expectedProduction +
", actualProduction=" + actualProduction +
", totalProduction=" + totalProduction +
", production=" + production +
", length='" + length + '\'' +
", width='" + width + '\'' +
", gsm='" + gsm + '\'' +
", wtPly='" + wtPly + '\'' +
", ply='" + ply + '\'' +
", cutPieces=" + cutPieces + ", cutPieces=" + cutPieces +
", title='" + title + '\'' + ", 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); processIds.add(8L);
return inventoryAccountDAO.findByIdsAndProcessIds( userInventoryAccountIds, processIds ); return inventoryAccountDAO.findByIdsAndProcessIds( userInventoryAccountIds, processIds );
} }
public List<InventoryAccount> getAllCuttingAccounts(){
return inventoryAccountDAO.findByParentEntityTypeAndParentId( "PROCESS", 1L );
}
} }

View File

@ -41,47 +41,64 @@ public class InventoryService {
this.stitchingOfflineItemDAO = stitchingOfflineItemDAO; 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 * receive inv from job card
* */ * */
@Transactional(rollbackFor = Exception.class) @Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void receiveJobCardInventory(long jobCardId, long accountId) { public void receiveJobCardInventory( long jobCardId, JobCardWrapper jobCardWrapper ) {
if (jobCardId == 0 || accountId == 0) { if ( jobCardId == 0 || jobCardWrapper.getItems( ) == null || jobCardWrapper.getItems( ).isEmpty( ) ) {
throw new RuntimeException("JobCard | Account can`t be empty"); throw new RuntimeException( " JobCard can`t be empty");
} }
JobCard jobCard = jobCardDAO.find( jobCardId ); JobCard jobCard = jobCardDAO.find( jobCardId );
// get job cad items // get job cad items
List<JobCardItem> items = jobCardItemDAO.findByCardId(jobCardId); List<JobCardItemWrapper> jobCardItemWrappers = jobCardWrapper.getItems( );
List<Long> jobCardItemWrapperIds = jobCardItemWrappers.stream( )
.map( JobCardItemWrapper::getJobCardItemId )
.collect( Collectors.toList( ) );
Map<Long,BigDecimal> jobCardItemIdToActualProdMap = jobCardItemWrappers.stream( )
.collect( Collectors.toMap( JobCardItemWrapper::getJobCardItemId, JobCardItemWrapper::getActualProduction ) );
List<JobCardItem> items = jobCardItemDAO.findByIds( jobCardItemWrapperIds );
if ( items != null && !items.isEmpty( ) ) { if ( items != null && !items.isEmpty( ) ) {
// get job card ite ids // get job card item ids
List<Long> jobCardItemIds = items.stream( ) List<Long> jobCardItemIds = items.stream( )
.map( JobCardItem::getId) .map( JobCardItem::getId)
.collect( Collectors.toList( )); .collect( Collectors.toList( ));
// id to item map // save updated cut pieces
Map<Long, JobCardItem> idToItemMap = items.stream() List<CutPiece> cutPieces = jobCardItemWrappers.stream( )
.collect(Collectors.toMap(JobCardItem::getId, Function.identity())); .flatMap( wrapper -> wrapper.getPieces( ).stream( ) )
.collect( Collectors.toList( ) );
cutPieceDAO.saveAll( cutPieces );
Map<Long, List<CutPiece>> piecesMap = cutPieceDAO.findByJobCardItemIds( jobCardItemIds) Map<Long, List<CutPiece>> piecesMap = cutPieceDAO.findByJobCardItemIds( jobCardItemIds)
.stream( ) .stream( )
.collect( Collectors.groupingBy( CutPiece::getJobCardItemId)); .collect( Collectors.groupingBy( CutPiece::getJobCardItemId));
// populate map
Map<JobCardItem, List<CutPiece>> jobCardItemtoPiecesMap = new HashMap<>();
for ( JobCardItem jobCardItem : items) { for ( JobCardItem jobCardItem : items) {
if (!jobCardItemtoPiecesMap.containsKey(jobCardItem)) {
jobCardItemtoPiecesMap.put(jobCardItem, piecesMap.getOrDefault(jobCardItem.getId(), new ArrayList<>()));
}
}
// create + save bundles // create + save bundles
List<Bundle> bundles = createBundles(jobCardId, jobCardItemtoPiecesMap); List<Bundle> bundles = createBundles( jobCardItem, piecesMap.get( jobCardItem.getId( ) ) );
// create transactions // create transactions
createTransactions(bundles, accountId, InventoryArtifactType.BUNDLE.name()); createTransactions( bundles, jobCardItem.getAccountId( ), InventoryArtifactType.BUNDLE.name( ));
jobCardItem.setActualProduction( jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ) , BigDecimal.ZERO ) );
}
// update items with quantity
jobCardItemDAO.saveAll( items );
// update job card inv status // update job card inv status
jobCard.setInventoryStatus(JobCard.InventoryStatus.RECEIVED.name()); updateJobCardInventoryStatus( jobCard );
jobCardDAO.save(jobCard);
} else { } else {
throw new RuntimeException( "Items Not found in Job Card"); throw new RuntimeException( "Items Not found in Job Card");
} }
@ -159,19 +176,17 @@ public class InventoryService {
// create bundles from cut pieces // create bundles from cut pieces
private List<Bundle> createBundles(long jobCardId, Map<JobCardItem, List<CutPiece>> jobCardItemtoPiecesMap) { private List<Bundle> createBundles( JobCardItem jobCardItem,
List<CutPiece> jobCardItemPieces ) {
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( ); Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
if (jobCardItemtoPiecesMap != null && !jobCardItemtoPiecesMap.isEmpty()) { if ( jobCardItemPieces != null && !jobCardItemPieces.isEmpty( )) {
List<Bundle> bundles = new ArrayList<>( ); 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 // create bundle against every cut piece
for (CutPiece cutPiece : value) { for ( CutPiece cutPiece : jobCardItemPieces ) {
Bundle bundle = new Bundle( ); Bundle bundle = new Bundle( );
bundle.setItemId(key.getItemId()); bundle.setItemId( jobCardItem.getItemId( ));
bundle.setSku(key.getSku()); bundle.setSku( jobCardItem.getSku( ));
bundle.setJobCardId(jobCardId); bundle.setJobCardId( jobCardItem.getJobCardId( ) );
bundle.setWrapQuantity( cutPiece.getQuantity( )); bundle.setWrapQuantity( cutPiece.getQuantity( ));
bundle.setType( cutPiece.getType( )); bundle.setType( cutPiece.getType( ));
bundle.setCreatedAt( LocalDateTime.now( )); bundle.setCreatedAt( LocalDateTime.now( ));
@ -183,7 +198,12 @@ public class InventoryService {
bundle.setId( bundleDAO.save( bundle)); 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 bundles;
} }
return new ArrayList<>( ); return new ArrayList<>( );
@ -193,7 +213,7 @@ public class InventoryService {
/* /*
* receive inventory from master barcode * receive inventory from master barcode
* */ * */
@Transactional(rollbackFor = Exception.class) @Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void receiveInventoryFromMasterBarcode( long masterId, long toAccount) { public void receiveInventoryFromMasterBarcode( long masterId, long toAccount) {
if ( masterId == 0 || toAccount == 0) { if ( masterId == 0 || toAccount == 0) {
throw new RuntimeException( "Master Barcode | Account can`t be empty"); throw new RuntimeException( "Master Barcode | Account can`t be empty");
@ -236,7 +256,7 @@ public class InventoryService {
throw new RuntimeException( "Item cant be Empty | null"); throw new RuntimeException( "Item cant be Empty | null");
} }
for ( JobCardItem jobCardItem : cardItems) { for ( JobCardItem jobCardItem : cardItems) {
int finalQuantity = jobCardItem.getExpectedProductionQuantity().compareTo(jobCardItem.getTotalProduction().add(jobCardItem.getProduction())); int finalQuantity = jobCardItem.getActualProduction( ).compareTo( jobCardItem.getTotalProduction( ).add( jobCardItem.getProduction( )));
if ( finalQuantity < 0) { if ( finalQuantity < 0) {
throw new RuntimeException( " Items cant be generated because it exceeds from limit of expected Production"); throw new RuntimeException( " Items cant be generated because it exceeds from limit of expected Production");
} }
@ -248,12 +268,11 @@ public class InventoryService {
if ( jobCardItems != null && !jobCardItems.isEmpty( ) ) { if ( jobCardItems != null && !jobCardItems.isEmpty( ) ) {
List<Long> itemIds = jobCardItems.stream().map(JobCardItem::getItemId).collect(Collectors.toList()); List<Long> itemIds = jobCardItems.stream( )
.filter( JobCardItem::getIsSelected )
.map( JobCardItem::getItemId).collect( Collectors.toList( ));
List<Bundle> bundles = bundleDAO.findByItemIdsAndCardId( itemIds, jobCardId); List<Bundle> bundles = bundleDAO.findByItemIdsAndCardId( itemIds, jobCardId);
List<Long> masterBundleIds = bundles.stream( ).map( Bundle::getMasterBundleId).collect( Collectors.toList( )); 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() ) );
Map<Long, MasterBundle> idToMasterBundleMap = masterBundleDAO.findByIds( masterBundleIds) Map<Long, MasterBundle> idToMasterBundleMap = masterBundleDAO.findByIds( masterBundleIds)
.stream( ) .stream( )
@ -272,7 +291,7 @@ public class InventoryService {
/* /*
* create finished items from master bundles * create finished items from master bundles
* */ * */
@Transactional(rollbackFor = Exception.class) @Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void createStitchingOfflineItemsFromJobCard( JobCard jobCard) { public void createStitchingOfflineItemsFromJobCard( JobCard jobCard) {
List<JobCardItem> jobCardItems = jobCard.getItems( ); List<JobCardItem> jobCardItems = jobCard.getItems( );
List<JobCardItem> updatedItems = new ArrayList<>( ); List<JobCardItem> updatedItems = new ArrayList<>( );
@ -282,9 +301,9 @@ public class InventoryService {
checkAllBundleAreReceived( jobCard.getId( ), jobCardItems); checkAllBundleAreReceived( jobCard.getId( ), jobCardItems);
for ( JobCardItem item : jobCardItems) { for ( JobCardItem item : jobCardItems) {
// select which has inventory // select which has inventory
if (!item.getProduction().equals(BigDecimal.ZERO)) { if ( item.getProduction( ).compareTo( BigDecimal.ZERO ) != 0 ) {
// production is completed out bundles // 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 // create out transactions of bundles in master bundles
List<Bundle> bundles = bundleDAO.findByItemIdAndCardId( item.getItemId( ), jobCard.getId( )); List<Bundle> bundles = bundleDAO.findByItemIdAndCardId( item.getItemId( ), jobCard.getId( ));
if ( bundles != null && !bundles.isEmpty( )) { if ( bundles != null && !bundles.isEmpty( )) {
@ -336,7 +355,7 @@ public class InventoryService {
stitchingOfflineItem.setItemId( jobCardItem.getItemId( )); stitchingOfflineItem.setItemId( jobCardItem.getItemId( ));
stitchingOfflineItem.setSku( jobCardItem.getSku( )); stitchingOfflineItem.setSku( jobCardItem.getSku( ));
stitchingOfflineItem.setJobCardId( jobCardItem.getId( )); stitchingOfflineItem.setJobCardId( jobCardItem.getId( ));
stitchingOfflineItem.setIsQa(true); stitchingOfflineItem.setIsQa( false );
long id = stitchingOfflineItemDAO.save( stitchingOfflineItem); long id = stitchingOfflineItemDAO.save( stitchingOfflineItem);
stitchingOfflineItem.setId( id); stitchingOfflineItem.setId( id);
stitchingOfflineItem.setBarcode( cryptographyService.generateRandomString( 15)); stitchingOfflineItem.setBarcode( cryptographyService.generateRandomString( 15));
@ -484,7 +503,7 @@ public class InventoryService {
/* /*
* segregate finish items * segregate finish items
* */ * */
@Transactional(rollbackFor = Exception.class) @Transactional( rollbackFor = Exception.class, propagation = Propagation.NESTED )
public void segregateFinishedItems( FinishedItemWrapper wrapper) { public void segregateFinishedItems( FinishedItemWrapper wrapper) {
if ( wrapper != null && wrapper.getItems( ) != null) { if ( wrapper != null && wrapper.getItems( ) != null) {

View File

@ -1,17 +1,12 @@
package com.utopiaindustries.service; package com.utopiaindustries.service;
import com.utopiaindustries.dao.ctp.CutPieceDAO; import com.utopiaindustries.dao.ctp.*;
import com.utopiaindustries.dao.ctp.CutPieceTypeDAO;
import com.utopiaindustries.dao.ctp.JobCardDAO;
import com.utopiaindustries.dao.ctp.JobCardItemDAO;
import com.utopiaindustries.dao.uind.ItemDAO; import com.utopiaindustries.dao.uind.ItemDAO;
import com.utopiaindustries.dao.uind.LocationSiteDAO; import com.utopiaindustries.dao.uind.LocationSiteDAO;
import com.utopiaindustries.dao.uind.PurchaseOrderDAO; import com.utopiaindustries.dao.uind.PurchaseOrderDAO;
import com.utopiaindustries.model.ctp.CutPiece; import com.utopiaindustries.model.ctp.*;
import com.utopiaindustries.model.ctp.CutPieceType;
import com.utopiaindustries.model.ctp.JobCard;
import com.utopiaindustries.model.ctp.JobCardItem;
import com.utopiaindustries.model.uind.Item; import com.utopiaindustries.model.uind.Item;
import com.utopiaindustries.querybuilder.ctp.JobCardQueryBuilder;
import com.utopiaindustries.util.StringUtils; import com.utopiaindustries.util.StringUtils;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@ -35,8 +30,9 @@ public class JobCardService {
private final ItemDAO itemDAO; private final ItemDAO itemDAO;
private final LocationSiteDAO locationSiteDAO; private final LocationSiteDAO locationSiteDAO;
private final PurchaseOrderDAO purchaseOrderDAO; 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.jobCardDAO = jobCardDAO;
this.cutPieceTypeDAO = cutPieceTypeDAO; this.cutPieceTypeDAO = cutPieceTypeDAO;
this.jobCardItemDAO = jobCardItemDAO; this.jobCardItemDAO = jobCardItemDAO;
@ -44,6 +40,7 @@ public class JobCardService {
this.itemDAO = itemDAO; this.itemDAO = itemDAO;
this.locationSiteDAO = locationSiteDAO; this.locationSiteDAO = locationSiteDAO;
this.purchaseOrderDAO = purchaseOrderDAO; this.purchaseOrderDAO = purchaseOrderDAO;
this.userInventoryAccountDAO = userInventoryAccountDAO;
} }
/* /*
@ -66,8 +63,30 @@ public class JobCardService {
/* /*
* get cards * get cards
* */ * */
public List<JobCard> getCards() { public List<JobCard> getCards( String id,
return jobCardDAO.findAll(); 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 * find card recursively
* */ * */
public JobCard findCardRecursively(long id) { 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); JobCard jobCard = jobCardDAO.find(id);
// set po and site titles // set po and site titles
jobCard.setPurchaseOrderTitle( purchaseOrderDAO.find( jobCard.getPurchaseOrderId() ).getCode() ); jobCard.setPurchaseOrderTitle( purchaseOrderDAO.find( jobCard.getPurchaseOrderId() ).getCode() );
@ -162,7 +233,6 @@ public class JobCardService {
} }
jobCard.setItems(items); jobCard.setItems(items);
return jobCard; return jobCard;
} }

View File

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

View File

@ -1,19 +1,41 @@
(async function () { (async function () {
Vue.prototype.$accounts = window.ctp.accounts;
Vue.prototype.$types = window.ctp.types; Vue.prototype.$types = window.ctp.types;
Vue.component('item-table', { Vue.component('job-card-items', {
props: ['items'], props: ['items'],
methods: { methods: {
removeItem: function (index) { 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 (confirm('Do want to delete Item?')) {
if (this.items[index].id === 0) { if (this.items[this.index].id === 0) {
this.items.splice(index, 1); this.items.splice(this.index, 1);
} else { } else {
// post request and reload page on success // post request and reload page on success
$.ajax({ $.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', method: 'POST',
contentType: 'application/json', contentType: 'application/json',
dataType: '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) { addPieces: function (e) {
e.preventDefault(); e.preventDefault();
@ -99,24 +87,67 @@
} }
}, },
template: ` template: `
<tr> <div class="form-row position-relative border-bottom my-4">
<td width="400">
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id"> <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 + '].sku'" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction"> <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 <item-search
v-bind:id-field-name="'items[' + index + '].itemId'" v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId" v-bind:id="item.itemId"
v-bind:title="item.title" v-bind:title="item.title"
v-on:item-select="onItemSelect" v-on:item-select="onItemSelect"
v-bind:show-label="false" v-bind:show-label="true"
v-bind:requuired="true"></item-search> v-bind:requuired="true">
</td> </item-search>
<td width="400"> </div>
<div class="col-sm-3 form-group">
<label>Sku</label>
<span class="form-control" readonly >{{item.sku}}</span> <span class="form-control" readonly >{{item.sku}}</span>
</td> </div>
<td width="500"> <div class="col-sm-2 form-group">
<span class="bi-plus-circle-fill" title="Add Pieces" v-on:click="addPieces"></span> <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" <cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex" v-bind:index="cIndex"
v-bind:pIndex="index" v-bind:pIndex="index"
@ -124,16 +155,15 @@
v-bind:key="index + '-' + cIndex" v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece"> v-on:piece-remove="removePiece">
</cut-piece> </cut-piece>
</td> <label class="d-block">&nbsp;</label>
<td width="200"> <a href="#" title="Add Cut Panels" class="btn btn-light text-left" v-on:click="addPieces" >
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-model="item.expectedProductionQuantity" required> <i class="bi-plus-circle-fill"></i>
</td> </a>
<td> </div>
<button class="btn btn-sm btn-light" title="Edit" v-on:click="removeItem"> </div>
<i class="bi bi-trash"></i>
</button>
</td> </div>
</tr>
` `
}); });
@ -186,7 +216,14 @@
'jobCardId': 0, 'jobCardId': 0,
'itemId': 0, 'itemId': 0,
'sku': '', 'sku': '',
'expectedProductionQuantity': 0.0, 'expectedProduction': 0.0,
'actualProduction' : 0.0,
'length' : '',
'width' : '',
'gsm' : '',
'wtPly' : '',
'ply' : '',
'accountId' : 0,
cutPieces: [] cutPieces: []
} }
}, },

View File

@ -1,14 +1,20 @@
( async function(){ ( async function(){
Vue.prototype.$types = window.ctp.types; Vue.prototype.$types = window.ctp.types;
Vue.prototype.$accounts = window.ctp.accounts;
Vue.component('item-rows', { Vue.component('item-rows', {
props: ['index', 'item'], props: ['index', 'item'],
methods : {
populateCuttingAccount : function (){
return this.$accounts.find(account => account.id === this.item.accountId).title;
},
},
template: ` template: `
<tr> <tr>
<td width="400"> <td width="400">
<input hidden="hidden" v-bind:value="item.id"> <input hidden="hidden" v-bind:name="'items[' + index + '].jobCardId'" v-bind:value="item.jobCardId" >
<input hidden="hidden" v-bind:value="item.sku"> <input hidden="hidden" v-bind:name="'items[' + index + '].jobCardItemId'" v-bind:value="item.id" >
<item-search <item-search
v-bind:id-field-name="'items[' + index + '].itemId'" v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId" v-bind:id="item.itemId"
@ -28,9 +34,14 @@
</cut-piece> </cut-piece>
</td> </td>
<td width="200"> <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> </td>
</tr> </tr>
` `
}); });
@ -46,10 +57,11 @@
}, },
template: ` template: `
<div class="row mt-1"> <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 + '].pieces[' + 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 + '].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"> <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 value="">Please Select</option>
<option v-for="(type,index) in $types" <option v-for="(type,index) in $types"
v-bind:selected="type.title === piece.type" v-bind:selected="type.title === piece.type"
@ -57,23 +69,27 @@
</select> </select>
</div> </div>
<div class="col-md-5"> <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>
</div> </div>
` `
}); });
Vue.component('job-card-details',{ Vue.component('job-card-details',{
props:[ 'jobCard' ], props:[ 'jobCard' ],
methods : {
},
template : ` template : `
<table class="table table-bordered bg-white col-sm-8"> <table class="table table-bordered bg-white col-sm-12">
<thead> <thead>
<tr> <tr>
<th>Item</th> <th>Item</th>
<th>Item Sku/Title</th> <th>Item Sku/Title</th>
<th>Cut Pieces</th> <th>Cut Pieces</th>
<th>Expected Production</th> <th>Expected Production</th>
<th>Actual Production</th>
<th>Account</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

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

View File

@ -59,8 +59,13 @@
</div> </div>
<div class="bg-light p-3 mb-3"> <div class="bg-light p-3 mb-3">
<h6 class="mb-3">Items</h6> <h6 class="mb-3">Items</h6>
<item-table v-bind:items.sync="items"> <job-card-item
</item-table> 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> <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"> <button class="btn btn-secondary btn-sm" v-on:click="addItem">
Add Item Add Item
@ -75,6 +80,7 @@
<script th:inline="javascript"> <script th:inline="javascript">
window.ctp.jobCard = [[${jobCard}]]; window.ctp.jobCard = [[${jobCard}]];
window.ctp.types = [[${cutPieceTypes}]] window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
</script> </script>
<script th:src="@{/js/vendor/compressor.min.js}"></script> <script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/job-card-form.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(), '')}}"> <form th:action="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}">
<h5 class="mb-4">Refine Your Search</h5> <h5 class="mb-4">Refine Your Search</h5>
<div class="form-group"> <div class="form-group">
<label>Title</label> <label>ID</label>
<input type="text" class="form-control" name="item-title" maxlength="100" th:value="${param['item-title']}"> <input type="text" class="form-control" name="id" maxlength="100" th:value="${param['id']}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Sku</label> <label>Code</label>
<input type="text" class="form-control" name="item-sku" maxlength="100" th:value="${param['item-sku']}"> <input type="text" class="form-control" name="code" maxlength="100" th:value="${param['code']}">
</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" >
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Status</label> <label>Status</label>
<select name="item-status" class="form-control"> <select class="form-control" name="status">
<option value="">All</option> <option value="">Please Select</option>
<option value="1" th:selected="${#strings.equals(param['item-status'], #strings.toString(1))}">Active</option> <option th:each="status: ${statuses}"
<option value="0" th:selected="${#strings.equals(param['item-status'], #strings.toString(0))}">Inactive</option> th:value="${status}"
th:text="${status}"
th:selected="${param['status'] == null ? false : #strings.equals(param['status'], status) }"></option>
</select> </select>
</div> </div>
<!-- number of items -->
<div class="form-group"> <div class="form-group">
<label>Number of Items</label> <label>Inventory Status</label>
<input type="number" class="form-control" name="item-count" th:value="(${param['item-count']} != null) ? ${param['item-count']} : 100"> <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> </div>
<input type="submit" class="btn btn-secondary btn-block" value="Search"> <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> <a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"
<button th:if="${isRequest}" class="btn btn-secondary btn-block">Reset</a>
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>
</form> </form>
</div> </div>
</aside> </aside>

View File

@ -26,7 +26,7 @@
</div> </div>
<div class="col-sm-3 form-group"> <div class="col-sm-3 form-group">
<label>Password</label> <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>
<div class="col-sm-3 form-group"> <div class="col-sm-3 form-group">
<label for="enable">Enabled</label> <label for="enable">Enabled</label>

View File

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

View File

@ -12,7 +12,8 @@
<h3 class="pb-2">Receive Inventory</h3> <h3 class="pb-2">Receive Inventory</h3>
<form th:action="@{/cutting/receive-inventory}" <form th:action="@{/cutting/receive-inventory}"
method="POST" method="POST"
id="receiveInvApp"> id="receiveInvApp"
th:object="${wrapper}">
<div class="bg-light p-3 mb-3"> <div class="bg-light p-3 mb-3">
<div class="form-row"> <div class="form-row">
<div class="col-sm-3 p-0"> <div class="col-sm-3 p-0">
@ -22,16 +23,16 @@
v-bind:required="true" v-bind:required="true"
></job-card-search> ></job-card-search>
</div> </div>
<div class="col-sm-3"> <!-- <div class="col-sm-3">-->
<label>Cutting Account</label> <!-- <label>Cutting Account</label>-->
<select class="form-control" name="account-id" required> <!-- <select class="form-control" name="account-id" required>-->
<option value="">Please Select</option> <!-- <option value="">Please Select</option>-->
<option th:each="account :${accounts}" <!-- <option th:each="account :${accounts}"-->
th:value="${account.id}" <!-- th:value="${account.id}"-->
th:text="${account.title}" <!-- th:text="${account.title}"-->
th:title="${account.notes}"></option> <!-- th:title="${account.notes}"></option>-->
</select> <!-- </select>-->
</div> <!-- </div>-->
</div> </div>
</div> </div>
<div class="bg-light p-3 mb-3" v-if="jobCard.id !== undefined"> <div class="bg-light p-3 mb-3" v-if="jobCard.id !== undefined">
@ -69,6 +70,7 @@
</form> </form>
<script th:inline="javascript"> <script th:inline="javascript">
window.ctp.types = [[${cutPieceTypes}]] window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
</script> </script>
<script th:src="@{/js/vendor/compressor.min.js}"></script> <script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/receive-inventory.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="*{id}"></td>
<td th:text="*{title}"></td> <td th:text="*{title}"></td>
<td th:text="*{parentEntityType}"></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 th:text="*{createdBy}"></td>
<td ctp:formatdatetime="*{createdAt}"></td> <td ctp:formatdatetime="*{createdAt}"></td>
<td > <td >
@ -96,7 +99,7 @@
else { else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show(); $row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({ $.ajax({
url: `/ctp/cutting/inventory-transactions?account-id=${accountId}`, url: `/ctp/inventory-transactions?account-id=${accountId}`,
success: function( data ){ success: function( data ){
// show fetched page // show fetched page
$row.child( data ).show(); $row.child( data ).show();
@ -119,7 +122,7 @@
else { else {
$row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show(); $row.child(`<span class="spinner-border text-center spinner-border-md" role="status"></span>`).show();
$.ajax({ $.ajax({
url: `/ctp/cutting/inventory-summary?account-id=${accountId}`, url: `/ctp/inventory-summary?account-id=${accountId}`,
success: function( data ){ success: function( data ){
// show fetched page // show fetched page
$row.child( data ).show(); $row.child( data ).show();

View File

@ -23,6 +23,10 @@
<th>Job Order</th> <th>Job Order</th>
<th>Status</th> <th>Status</th>
<th>Inventory 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 Date</th>
<th>Added By</th> <th>Added By</th>
<th>Actions</th> <th>Actions</th>
@ -40,6 +44,14 @@
<span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span> <span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span>
<span th:unless="*{inventoryStatus}">-</span> <span th:unless="*{inventoryStatus}">-</span>
</td> </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 ctp:formatdatetime="*{createdAt}"></td>
<td th:text="*{createdBy}"></td> <td th:text="*{createdBy}"></td>
<td> <td>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,41 @@
(async function () { (async function () {
Vue.prototype.$accounts = window.ctp.accounts;
Vue.prototype.$types = window.ctp.types; Vue.prototype.$types = window.ctp.types;
Vue.component('item-table', { Vue.component('job-card-items', {
props: ['items'], props: ['items'],
methods: { methods: {
removeItem: function (index) { 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 (confirm('Do want to delete Item?')) {
if (this.items[index].id === 0) { if (this.items[this.index].id === 0) {
this.items.splice(index, 1); this.items.splice(this.index, 1);
} else { } else {
// post request and reload page on success // post request and reload page on success
$.ajax({ $.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', method: 'POST',
contentType: 'application/json', contentType: 'application/json',
dataType: '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) { addPieces: function (e) {
e.preventDefault(); e.preventDefault();
@ -99,24 +87,67 @@
} }
}, },
template: ` template: `
<tr> <div class="form-row position-relative border-bottom my-4">
<td width="400">
<input hidden="hidden" v-bind:name="'items[' + index + '].id'" v-bind:value="item.id"> <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 + '].sku'" v-bind:value="item.sku">
<input hidden="hidden" v-bind:name="'items[' + index + '].totalProduction'" v-bind:value="item.totalProduction"> <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 <item-search
v-bind:id-field-name="'items[' + index + '].itemId'" v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId" v-bind:id="item.itemId"
v-bind:title="item.title" v-bind:title="item.title"
v-on:item-select="onItemSelect" v-on:item-select="onItemSelect"
v-bind:show-label="false" v-bind:show-label="true"
v-bind:requuired="true"></item-search> v-bind:requuired="true">
</td> </item-search>
<td width="400"> </div>
<div class="col-sm-3 form-group">
<label>Sku</label>
<span class="form-control" readonly >{{item.sku}}</span> <span class="form-control" readonly >{{item.sku}}</span>
</td> </div>
<td width="500"> <div class="col-sm-2 form-group">
<span class="bi-plus-circle-fill" title="Add Pieces" v-on:click="addPieces"></span> <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" <cut-piece v-for="(piece, cIndex) in item.cutPieces"
v-bind:index="cIndex" v-bind:index="cIndex"
v-bind:pIndex="index" v-bind:pIndex="index"
@ -124,16 +155,15 @@
v-bind:key="index + '-' + cIndex" v-bind:key="index + '-' + cIndex"
v-on:piece-remove="removePiece"> v-on:piece-remove="removePiece">
</cut-piece> </cut-piece>
</td> <label class="d-block">&nbsp;</label>
<td width="200"> <a href="#" title="Add Cut Panels" class="btn btn-light text-left" v-on:click="addPieces" >
<input type="number" class="form-control" v-bind:name="'items[' + index + '].expectedProductionQuantity'" v-model="item.expectedProductionQuantity" required> <i class="bi-plus-circle-fill"></i>
</td> </a>
<td> </div>
<button class="btn btn-sm btn-light" title="Edit" v-on:click="removeItem"> </div>
<i class="bi bi-trash"></i>
</button>
</td> </div>
</tr>
` `
}); });
@ -186,7 +216,14 @@
'jobCardId': 0, 'jobCardId': 0,
'itemId': 0, 'itemId': 0,
'sku': '', 'sku': '',
'expectedProductionQuantity': 0.0, 'expectedProduction': 0.0,
'actualProduction' : 0.0,
'length' : '',
'width' : '',
'gsm' : '',
'wtPly' : '',
'ply' : '',
'accountId' : 0,
cutPieces: [] cutPieces: []
} }
}, },

View File

@ -1,14 +1,20 @@
( async function(){ ( async function(){
Vue.prototype.$types = window.ctp.types; Vue.prototype.$types = window.ctp.types;
Vue.prototype.$accounts = window.ctp.accounts;
Vue.component('item-rows', { Vue.component('item-rows', {
props: ['index', 'item'], props: ['index', 'item'],
methods : {
populateCuttingAccount : function (){
return this.$accounts.find(account => account.id === this.item.accountId).title;
},
},
template: ` template: `
<tr> <tr>
<td width="400"> <td width="400">
<input hidden="hidden" v-bind:value="item.id"> <input hidden="hidden" v-bind:name="'items[' + index + '].jobCardId'" v-bind:value="item.jobCardId" >
<input hidden="hidden" v-bind:value="item.sku"> <input hidden="hidden" v-bind:name="'items[' + index + '].jobCardItemId'" v-bind:value="item.id" >
<item-search <item-search
v-bind:id-field-name="'items[' + index + '].itemId'" v-bind:id-field-name="'items[' + index + '].itemId'"
v-bind:id="item.itemId" v-bind:id="item.itemId"
@ -28,9 +34,14 @@
</cut-piece> </cut-piece>
</td> </td>
<td width="200"> <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> </td>
</tr> </tr>
` `
}); });
@ -46,10 +57,11 @@
}, },
template: ` template: `
<div class="row mt-1"> <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 + '].pieces[' + 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 + '].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"> <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 value="">Please Select</option>
<option v-for="(type,index) in $types" <option v-for="(type,index) in $types"
v-bind:selected="type.title === piece.type" v-bind:selected="type.title === piece.type"
@ -57,23 +69,27 @@
</select> </select>
</div> </div>
<div class="col-md-5"> <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>
</div> </div>
` `
}); });
Vue.component('job-card-details',{ Vue.component('job-card-details',{
props:[ 'jobCard' ], props:[ 'jobCard' ],
methods : {
},
template : ` template : `
<table class="table table-bordered bg-white col-sm-8"> <table class="table table-bordered bg-white col-sm-12">
<thead> <thead>
<tr> <tr>
<th>Item</th> <th>Item</th>
<th>Item Sku/Title</th> <th>Item Sku/Title</th>
<th>Cut Pieces</th> <th>Cut Pieces</th>
<th>Expected Production</th> <th>Expected Production</th>
<th>Actual Production</th>
<th>Account</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

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

View File

@ -59,8 +59,13 @@
</div> </div>
<div class="bg-light p-3 mb-3"> <div class="bg-light p-3 mb-3">
<h6 class="mb-3">Items</h6> <h6 class="mb-3">Items</h6>
<item-table v-bind:items.sync="items"> <job-card-item
</item-table> 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> <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"> <button class="btn btn-secondary btn-sm" v-on:click="addItem">
Add Item Add Item
@ -75,6 +80,7 @@
<script th:inline="javascript"> <script th:inline="javascript">
window.ctp.jobCard = [[${jobCard}]]; window.ctp.jobCard = [[${jobCard}]];
window.ctp.types = [[${cutPieceTypes}]] window.ctp.types = [[${cutPieceTypes}]]
window.ctp.accounts = [[${accounts}]]
</script> </script>
<script th:src="@{/js/vendor/compressor.min.js}"></script> <script th:src="@{/js/vendor/compressor.min.js}"></script>
<script th:src="@{/js/job-card-form.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(), '')}}"> <form th:action="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}">
<h5 class="mb-4">Refine Your Search</h5> <h5 class="mb-4">Refine Your Search</h5>
<div class="form-group"> <div class="form-group">
<label>Title</label> <label>ID</label>
<input type="text" class="form-control" name="item-title" maxlength="100" th:value="${param['item-title']}"> <input type="text" class="form-control" name="id" maxlength="100" th:value="${param['id']}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Sku</label> <label>Code</label>
<input type="text" class="form-control" name="item-sku" maxlength="100" th:value="${param['item-sku']}"> <input type="text" class="form-control" name="code" maxlength="100" th:value="${param['code']}">
</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" >
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Status</label> <label>Status</label>
<select name="item-status" class="form-control"> <select class="form-control" name="status">
<option value="">All</option> <option value="">Please Select</option>
<option value="1" th:selected="${#strings.equals(param['item-status'], #strings.toString(1))}">Active</option> <option th:each="status: ${statuses}"
<option value="0" th:selected="${#strings.equals(param['item-status'], #strings.toString(0))}">Inactive</option> th:value="${status}"
th:text="${status}"
th:selected="${param['status'] == null ? false : #strings.equals(param['status'], status) }"></option>
</select> </select>
</div> </div>
<!-- number of items -->
<div class="form-group"> <div class="form-group">
<label>Number of Items</label> <label>Inventory Status</label>
<input type="number" class="form-control" name="item-count" th:value="(${param['item-count']} != null) ? ${param['item-count']} : 100"> <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> </div>
<input type="submit" class="btn btn-secondary btn-block" value="Search"> <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> <a th:href="@{${#strings.replace(#httpServletRequest.requestURI, #request.getContextPath(), '')}}"
<button th:if="${isRequest}" class="btn btn-secondary btn-block">Reset</a>
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>
</form> </form>
</div> </div>
</aside> </aside>

View File

@ -26,7 +26,7 @@
</div> </div>
<div class="col-sm-3 form-group"> <div class="col-sm-3 form-group">
<label>Password</label> <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>
<div class="col-sm-3 form-group"> <div class="col-sm-3 form-group">
<label for="enable">Enabled</label> <label for="enable">Enabled</label>

View File

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

View File

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

View File

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

View File

@ -23,6 +23,10 @@
<th>Job Order</th> <th>Job Order</th>
<th>Status</th> <th>Status</th>
<th>Inventory 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 Date</th>
<th>Added By</th> <th>Added By</th>
<th>Actions</th> <th>Actions</th>
@ -40,6 +44,14 @@
<span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span> <span class="badge" th:classappend="'badge-' + *{inventoryStatus}" th:if="*{inventoryStatus}" th:text="*{inventoryStatus}"></span>
<span th:unless="*{inventoryStatus}">-</span> <span th:unless="*{inventoryStatus}">-</span>
</td> </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 ctp:formatdatetime="*{createdAt}"></td>
<td th:text="*{createdBy}"></td> <td th:text="*{createdBy}"></td>
<td> <td>

View File

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

View File

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

View File

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

View File

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

View File

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