fixed manually enter bundle Quantity and Total production and Qr field scan autofocus and Barcode scan Field autofocus
parent
f619001e5f
commit
4ad26f4fa6
|
@ -24,9 +24,10 @@ public class JobCardItemDAO {
|
|||
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_AND_ITEM_ID = String.format( "SELECT * FROM %s WHERE job_card_id = :card_id AND item_id = :item_id ", 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 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, is_complete) VALUES (:id, :job_card_id, :item_id, :sku, :expected_production, :actual_production, :total_production, :account_id, :length, :width, :gsm, :wt_ply, :ply, :is_complete) 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), is_complete =VALUES(is_complete) ", 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 );
|
||||
private final String SELECT_BY_JOB_CARD_AND_ACCOUNT_IDS = String.format( "SELECT * FROM %s WHERE job_card_id = :job_card_id AND account_id IN (:account_ids) AND is_complete = FALSE ", TABLE_NAME );
|
||||
private final String SELECT_ALL_ACTIVE_ITEM = String.format("SELECT CASE WHEN MIN(is_complete) = TRUE THEN TRUE ELSE FALSE END FROM %s WHERE job_card_id = :job_card_id AND id IN (:id)", TABLE_NAME);
|
||||
|
||||
public JobCardItemDAO(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
|
||||
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
|
||||
|
@ -47,7 +48,9 @@ public class JobCardItemDAO {
|
|||
.addValue("width", jobCardItem.getWidth() )
|
||||
.addValue("gsm", jobCardItem.getGsm() )
|
||||
.addValue("wt_ply", jobCardItem.getWtPly() )
|
||||
.addValue("ply", jobCardItem.getPly() );
|
||||
.addValue("ply", jobCardItem.getPly() )
|
||||
.addValue("is_complete", jobCardItem.isComplete() );
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
|
@ -112,12 +115,20 @@ public class JobCardItemDAO {
|
|||
return namedParameterJdbcTemplate.query( SELECT_BY_IDS, params, new JobCardItemRowMapper() );
|
||||
}
|
||||
|
||||
public List<JobCardItem> findByJobCardAndAccountIdsAndIsReceived( Long jobCardId, Long actualProduction, List<Long> accountIds ){
|
||||
public List<JobCardItem> findByJobCardAndAccountIdsAndIsReceived( Long jobCardId, 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() );
|
||||
}
|
||||
|
||||
public boolean checkAllItemsComplete( Long jobCardId, List<Long> itemsId ){
|
||||
if( itemsId == null || itemsId.isEmpty() ) return false;
|
||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
||||
params.addValue( "id", itemsId );
|
||||
params.addValue("job_card_id", jobCardId );
|
||||
Boolean allComplete = namedParameterJdbcTemplate.queryForObject(SELECT_ALL_ACTIVE_ITEM, params, Boolean.class);
|
||||
return Boolean.TRUE.equals(allComplete);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ public class JobCardItem {
|
|||
private List<CutPiece> cutPieces;
|
||||
private String title;
|
||||
private boolean isSelected;
|
||||
private boolean isComplete;
|
||||
|
||||
public JobCardItem() {
|
||||
this.expectedProduction = BigDecimal.ZERO;
|
||||
|
@ -167,6 +168,14 @@ public class JobCardItem {
|
|||
isSelected = selected;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
isComplete = complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -9,6 +9,8 @@ public class JobCardItemWrapper {
|
|||
private long jobCardItemId;
|
||||
private List<CutPiece> pieces;
|
||||
private BigDecimal actualProduction;
|
||||
private int perBundleQuantity;
|
||||
private boolean finalReceived;
|
||||
|
||||
public long getJobCardId() {
|
||||
return jobCardId;
|
||||
|
@ -42,6 +44,22 @@ public class JobCardItemWrapper {
|
|||
this.actualProduction = actualProduction;
|
||||
}
|
||||
|
||||
public int getPerBundleQuantity() {
|
||||
return perBundleQuantity;
|
||||
}
|
||||
|
||||
public void setPerBundleQuantity(int perBundleQuantity) {
|
||||
this.perBundleQuantity = perBundleQuantity;
|
||||
}
|
||||
|
||||
public boolean getFinalReceived() {
|
||||
return finalReceived;
|
||||
}
|
||||
|
||||
public void setFinalReceived(boolean finalReceived) {
|
||||
this.finalReceived = finalReceived;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JobCardItemWrapper{" +
|
||||
|
|
|
@ -73,6 +73,7 @@ public class InventoryService {
|
|||
.collect( Collectors.toMap( JobCardItemWrapper::getJobCardItemId, JobCardItemWrapper::getActualProduction ) );
|
||||
|
||||
List<JobCardItem> items = jobCardItemDAO.findByIds( jobCardItemWrapperIds );
|
||||
|
||||
if ( items != null && !items.isEmpty( ) ) {
|
||||
// get job card item ids
|
||||
List<Long> jobCardItemIds = items.stream( )
|
||||
|
@ -90,16 +91,38 @@ public class InventoryService {
|
|||
.collect( Collectors.groupingBy( CutPiece::getJobCardItemId));
|
||||
|
||||
for ( JobCardItem jobCardItem : items) {
|
||||
// create + save bundles
|
||||
List<Bundle> bundles = createBundles( jobCardItem, piecesMap.get( jobCardItem.getId( ) ),jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ) , BigDecimal.ZERO ) );
|
||||
|
||||
int quantity = jobCardItemWrappers.stream()
|
||||
.filter(e -> e.getJobCardItemId() == jobCardItem.getId())
|
||||
.mapToInt(JobCardItemWrapper::getPerBundleQuantity)
|
||||
.findFirst()
|
||||
.orElse(0);
|
||||
|
||||
boolean cuttingComplete = jobCardItemWrappers.stream()
|
||||
.filter(e -> e.getJobCardItemId() == jobCardItem.getId())
|
||||
.map(JobCardItemWrapper::getFinalReceived)
|
||||
.findFirst()
|
||||
.orElse(false);
|
||||
|
||||
BigDecimal production = jobCardItemWrappers.stream()
|
||||
.filter(e -> e.getJobCardItemId() == jobCardItem.getId())
|
||||
.map(JobCardItemWrapper::getActualProduction)
|
||||
.findFirst()
|
||||
.orElse(BigDecimal.ZERO);
|
||||
|
||||
List<Bundle> bundles = createBundles( jobCardItem,quantity,jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ) , BigDecimal.ZERO ) );
|
||||
// create transactions
|
||||
createTransactions( bundles, jobCardItem.getAccountId( ), InventoryArtifactType.BUNDLE.name( ));
|
||||
jobCardItem.setActualProduction( jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ) , BigDecimal.ZERO ) );
|
||||
jobCardItem.setActualProduction( jobCardItemIdToActualProdMap.getOrDefault( jobCardItem.getId( ), BigDecimal.ZERO ).add(jobCardItem.getActualProduction()) );
|
||||
jobCardItem.setComplete(cuttingComplete);
|
||||
|
||||
}
|
||||
// update items with quantity
|
||||
jobCardItemDAO.saveAll( items );
|
||||
// update job card inv status
|
||||
if(jobCardItemDAO.checkAllItemsComplete(jobCardId,jobCardItemIds)) {
|
||||
updateJobCardInventoryStatus(jobCard);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException( "Items Not found in Job Card");
|
||||
}
|
||||
|
@ -182,29 +205,12 @@ public class InventoryService {
|
|||
|
||||
// create bundles from cut pieces
|
||||
private List<Bundle> createBundles( JobCardItem jobCardItem,
|
||||
List<CutPiece> jobCardItemPieces, BigDecimal value ) {
|
||||
int perBundleWrap, BigDecimal value ) {
|
||||
Authentication authentication = SecurityContextHolder.getContext( ).getAuthentication( );
|
||||
if ( value != null && !value.equals(BigDecimal.ZERO)) {
|
||||
List<Bundle> bundles = new ArrayList<>( );
|
||||
// create bundle against every cut piece
|
||||
if(value.intValue()<=20){
|
||||
Bundle bundle = new Bundle( );
|
||||
bundle.setItemId( jobCardItem.getItemId( ));
|
||||
bundle.setSku( jobCardItem.getSku( ));
|
||||
bundle.setJobCardId( jobCardItem.getJobCardId( ) );
|
||||
bundle.setWrapQuantity(value);
|
||||
bundle.setType( "BUNDLE");
|
||||
bundle.setCreatedAt( LocalDateTime.now( ));
|
||||
bundle.setCreatedBy( authentication.getName( ));
|
||||
bundles.add( bundle);
|
||||
bundle.setId( bundleDAO.save( bundle));
|
||||
bundle.setBarcode( cryptographyService.generateRandomString( 15));
|
||||
// save again after barcode generation
|
||||
bundle.setId( bundleDAO.save( bundle));
|
||||
}else{
|
||||
int quantity = value.intValue();
|
||||
int batchSize = 20;
|
||||
|
||||
int batchSize = perBundleWrap;
|
||||
int iterations = (int) Math.ceil((double) quantity / batchSize);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
|
@ -225,8 +231,6 @@ public class InventoryService {
|
|||
// save again after barcode generation
|
||||
bundle.setId( bundleDAO.save( bundle));
|
||||
}
|
||||
|
||||
}
|
||||
// for ( Map.Entry<JobCardItem, List<CutPiece>> entry : jobCardItemPieces ) {
|
||||
// JobCardItem key = entry.getKey( );
|
||||
// List<CutPiece> value = entry.getValue( );
|
||||
|
|
|
@ -184,7 +184,7 @@ public class JobCardService {
|
|||
.collect( Collectors.toList() );
|
||||
|
||||
// get items has account ids and has actual production not filled
|
||||
List<JobCardItem> items = jobCardItemDAO.findByJobCardAndAccountIdsAndIsReceived( id, 0L ,accountIds );
|
||||
List<JobCardItem> items = jobCardItemDAO.findByJobCardAndAccountIdsAndIsReceived( id ,accountIds );
|
||||
if (items != null && !items.isEmpty()) {
|
||||
// get job card ite ids
|
||||
List<Long> jobCardItemIds = items.stream()
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
},
|
||||
methods : {
|
||||
onItemSelect: function (id, item) {
|
||||
console.log("wdwawdwwadwwdwda",item.id)
|
||||
this.items.push(item);
|
||||
},
|
||||
removeItem: function (index) {
|
||||
|
|
|
@ -4,23 +4,27 @@
|
|||
Vue.prototype.$accounts = window.ctp.accounts;
|
||||
|
||||
Vue.component('item-rows', {
|
||||
data() {
|
||||
return {
|
||||
wrapQuantity: 0
|
||||
};
|
||||
},
|
||||
props: ['index', 'item'],
|
||||
methods : {
|
||||
populateCuttingAccount : function (){
|
||||
return this.$accounts.find(account => account.id === this.item.accountId).title;
|
||||
},
|
||||
handleValueChange : function(value){
|
||||
this.wrapQuantity = value
|
||||
}
|
||||
|
||||
},
|
||||
template: `
|
||||
<tr>
|
||||
<td width="400">
|
||||
<td width="120">
|
||||
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardId'" v-bind:value="item.jobCardId" >
|
||||
<input hidden="hidden" v-bind:name="'items[' + index + '].jobCardItemId'" v-bind:value="item.id" >
|
||||
<item-search
|
||||
v-bind:id-field-name="'items[' + index + '].itemId'"
|
||||
v-bind:id="item.itemId"
|
||||
v-bind:type="item.type"
|
||||
v-bind:show-label="false"
|
||||
v-bind:disabled="true"></item-search>
|
||||
<span class="form-control" readonly>{{item.id}}</span>
|
||||
</td>
|
||||
<td width="400">
|
||||
<span class="form-control" readonly >{{item.sku}}</span>
|
||||
|
@ -36,8 +40,17 @@
|
|||
<td width="200">
|
||||
<span class="form-control" readonly>{{item.expectedProduction}}</span>
|
||||
</td>
|
||||
<td width="100">
|
||||
<span class="form-control" readonly>{{item.actualProduction}}</span>
|
||||
</td>
|
||||
<td width="200">
|
||||
<input class="form-control" min="0" type="number" v-bind:name="'items[' + index + '].actualProduction'" required>
|
||||
<input class="form-control" @input="handleValueChange($event.target.value)" :min="0" type="number" v-bind:name="'items[' + index + '].actualProduction'" required>
|
||||
</td>
|
||||
<td width="200">
|
||||
<input class="form-control" min="1" :max="wrapQuantity" type="number" v-bind:name="'items[' + index + '].perBundleQuantity'" required>
|
||||
</td>
|
||||
<td width="10" style="text-align: center;" >
|
||||
<input type="checkbox" v-bind:name="'items[' + index + '].finalReceived'">
|
||||
</td>
|
||||
<td>
|
||||
{{ populateCuttingAccount() }}
|
||||
|
@ -84,11 +97,14 @@
|
|||
<table class="table table-bordered bg-white w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>ID</th>
|
||||
<th>Item Sku/Title</th>
|
||||
<th>Cut Pieces</th>
|
||||
<th>Expected Production</th>
|
||||
<th>Current Production</th>
|
||||
<th>Actual Production</th>
|
||||
<th>Per Bundle Quantity</th>
|
||||
<th>Cutting Complete</th>
|
||||
<th style="width: 312px" >Account</th>
|
||||
</tr>
|
||||
</tr>
|
||||
|
|
|
@ -216,6 +216,7 @@ if ( typeof Vue !== 'undefined' ) {
|
|||
v-bind:disabled="disabled"
|
||||
v-bind:readonly="readOnly"
|
||||
v-bind:inputmode="inputMode"
|
||||
autofocus
|
||||
v-bind:class="{ 'is-invalid': ( showInputErrorOnZeroId && ( entityId === 0 || entityId == null ) ) }"
|
||||
autocomplete="off">
|
||||
<!-- autocomplete list -->
|
||||
|
@ -3525,43 +3526,75 @@ if ( typeof Vue !== 'undefined' ) {
|
|||
});
|
||||
|
||||
|
||||
/*
|
||||
* finished item search
|
||||
* */
|
||||
Vue.component('finished-item-search',{
|
||||
mixins: [searchComponentMixin],
|
||||
methods : {
|
||||
getSearchUrl : function () {
|
||||
return `/ctp/rest/finished-items/search?term=${encodeURIComponent( this.list.term )}&is-segregated=${this.isSegregated}`
|
||||
},
|
||||
getEmittedEventName: function() {
|
||||
return 'finished-item-select';
|
||||
},
|
||||
getTitle: function( item ) {
|
||||
return `${item.id} - ( ${item.barcode} )`;
|
||||
}
|
||||
},
|
||||
Vue.component('search-item', {
|
||||
props: {
|
||||
labelText: {
|
||||
label: {
|
||||
type: String,
|
||||
default: 'Search Finished Item'
|
||||
},
|
||||
titleFieldName: {
|
||||
default: 'title'
|
||||
},
|
||||
idFieldName: {
|
||||
default: 'id'
|
||||
},
|
||||
codeFieldName : {
|
||||
default : 'code'
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isSegregated: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inputMode: {
|
||||
default : 'none'
|
||||
debounceTime: {
|
||||
type: Number,
|
||||
default: 500
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchTerm: '',
|
||||
timeout: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleInput() {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, this.debounceTime);
|
||||
},
|
||||
async fetchData() {
|
||||
if (this.searchTerm.trim() === '') return;
|
||||
try {
|
||||
const response = await fetch(`${this.url}?term=${encodeURIComponent(this.searchTerm)}&is-segregated=${this.isSegregated}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.length > 0) {
|
||||
const selectedItem = data[0];
|
||||
this.$emit('finished-item-select', selectedItem.id, selectedItem);
|
||||
this.searchTerm = `${selectedItem.id} - (${selectedItem.barcode})`;
|
||||
setTimeout(() => {
|
||||
this.searchTerm = '';
|
||||
}, 500);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.searchTerm = '';
|
||||
}, 500);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching search results:', error);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="search-container">
|
||||
<label>{{ label }}</label>
|
||||
<input type="text" class="form-control"
|
||||
v-model="searchTerm"
|
||||
@input="handleInput"
|
||||
placeholder="Scan QR"
|
||||
autocomplete="off"
|
||||
inputmode="none"
|
||||
autofocus>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
||||
/*
|
||||
* bundle search component
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
<div class="bg-light p-3 mb-3">
|
||||
<div class="form-row">
|
||||
<div class="col-sm-3">
|
||||
<bundle-search
|
||||
v-on:bundle-select="onBundleSelect"
|
||||
></bundle-search>
|
||||
<search-item
|
||||
label="Search Bundle"
|
||||
url="/ctp/rest/bundles/search"
|
||||
v-on:finished-item-select="onBundleSelect">
|
||||
</search-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
v-on:job-card-select="onCardSelect"
|
||||
v-bind:required="true"
|
||||
></job-card-search>
|
||||
|
||||
</div>
|
||||
<!-- <div class="col-sm-3">-->
|
||||
<!-- <label>Cutting Account</label>-->
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
<div class="bg-light p-3 mb-3">
|
||||
<div class="form-row">
|
||||
<div class="col-sm-3 form-group">
|
||||
<finished-item-search
|
||||
v-bind:is-segregated="false"
|
||||
v-on:finished-item-select="onItemSelect"
|
||||
>
|
||||
</finished-item-search>
|
||||
<search-item
|
||||
url="/ctp/rest/finished-items/search"
|
||||
v-on:finished-item-select="onItemSelect">
|
||||
</search-item>
|
||||
</div>
|
||||
<div class="col-sm-3 form-group">
|
||||
<!-- <label>Packaging Account</label>-->
|
||||
|
|
|
@ -13,12 +13,13 @@
|
|||
<form th:action="'/ctp/quality-control/qc-finished-item'" method="post" id="qcForm"
|
||||
th:object="${wrapper}">
|
||||
<div class="bg-light p-3 mb-3">
|
||||
<h6 class="mb-3">Search Stitched Item</h6>
|
||||
<div class="form-row">
|
||||
<div class="col-sm-3 form-group">
|
||||
<stitching-offline-item
|
||||
v-on:stitching-offline-item-select="onItemSelect"
|
||||
></stitching-offline-item>
|
||||
<search-item
|
||||
label="Search Stitch Item"
|
||||
url="/ctp/rest/stitching-offline-items/search"
|
||||
v-on:finished-item-select="onItemSelect">
|
||||
</search-item>
|
||||
</div>
|
||||
<div class="col-sm-3 form-group">
|
||||
<label>Finishing Account</label>
|
||||
|
|
Loading…
Reference in New Issue