Skip to content

Commit

Permalink
display lot barcode
Browse files Browse the repository at this point in the history
  • Loading branch information
mbayopanda committed Jan 27, 2022
1 parent ec3b2e8 commit 3a69ccb
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 5 deletions.
1 change: 1 addition & 0 deletions client/src/i18n/fr/barcode.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"BARCODE" : {
"BARCODE": "Code-barre",
"SCAN": "Scanner",
"SCAN_BARCODE" : "Scanner le code-barre",
"SCAN_DOCUMENT" : "Scanner le code-barres du document",
"AWAITING_INPUT" : "En Attente d'Entrée",
"AWAITING_HTTP" : "Code-barres lu! Recherche l'enregistrement....",
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/fr/stock.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
"INVENTORY_ADJUSTMENT" : "Ajustement de stock"
},
"LOTS" : {
"BARCODE_FOR_LOT" : "Code-barre pour le lot",
"REGISTRY" : "Registre des lots",
"MERGED_LOTS_AUTOMATICALLY": "{{NumLots}} lots fusionnés automatiquement pour {{numInventories}} articles d'inventaire",
"ENABLE_CORRECTING_LOT_EXPIRATION_DATES": "Permettre la correction des dates d'expiration des lots",
Expand Down
12 changes: 12 additions & 0 deletions client/src/js/services/receipts/ReceiptModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ function ReceiptModal(Modal, Receipts, Invoice, Cash, Voucher) {
service.stockAssignReceipt = stockAssignReceipt;
service.stockRequisitionReceipt = stockRequisitionReceipt;
service.getReceiptFnByFluxId = getReceiptFnByFluxId;
service.lotBarcodeReceipt = lotBarcodeReceipt;

/**
* @method stockRequisitionReceipt
Expand Down Expand Up @@ -373,6 +374,17 @@ function ReceiptModal(Modal, Receipts, Invoice, Cash, Voucher) {
return ReceiptFactory(promise, opts);
}

/**
* @method lotBarcodeReceipt
* @param {string} uuid
* @param {boolean} notifyCreated
*/
function lotBarcodeReceipt(uuid, notifyCreated) {
const opts = { title : 'LOTS.BARCODE_FOR_LOT', notifyCreated, renderer : Receipts.renderer };
const promise = Receipts.lotBarcodeReceipt(uuid, { renderer : opts.renderer });
return ReceiptFactory(promise, opts);
}

/**
* @method stockExitLossReceipt
* @param {string} documentUuid
Expand Down
8 changes: 8 additions & 0 deletions client/src/js/services/receipts/ReceiptService.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ function ReceiptService($http, util, Language, AppCache, Session) {
service.stockRequisitionReceipt = stockRequisitionReceipt;
service.stockAdjustmentReport = stockAdjustmentReport;
service.stockAggregateConsumptionReceipt = stockAggregateConsumptionReceipt;
service.lotBarcodeReceipt = lotBarcodeReceipt;

// lot barcode
function lotBarcodeReceipt(uuid, options) {
options.posReceipt = service.posReceipt;
const route = `/receipts/stock/lots/${uuid}/barcode`;
return fetch(route, options);
}

// stock requisition receipt
function stockRequisitionReceipt(uuid, options) {
Expand Down
1 change: 1 addition & 0 deletions client/src/modules/stock/StockFilterer.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function StockFiltererService(Filters, AppCache, $httpParamSerializer, Languages
{ key : 'invoice_uuid', label : 'FORM.LABELS.INVOICE' },
{ key : 'group_uuid', label : 'STOCK.INVENTORY_GROUP' },
{ key : 'label', label : 'STOCK.LOT' },
{ key : 'barcode', label : 'BARCODE.BARCODE' },
{ key : 'is_exit', label : 'STOCK.OUTPUT', valueFilter : 'boolean' },
{ key : 'reference', label : 'FORM.LABELS.REFERENCE' },
{ key : 'flux_id', label : 'STOCK.FLUX' },
Expand Down
5 changes: 5 additions & 0 deletions client/src/modules/stock/lots/registry.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<li role="separator" class="divider"></li>
<li role="menuitem" bh-require-enterprise-setting="barcodes">
<a href ng-click="StockLotsCtrl.openBarcodeScanner()" data-action="scan-barcode">
<span class="fa fa-barcode"></span> <span translate>BARCODE.SCAN</span>
</a>
</li>
<li role="menuitem" bh-require-enterprise-setting="barcodes">
<a href ng-click="StockLotsCtrl.openLotBarcodeScanner()" data-action="scan-barcode">
<span class="fa fa-barcode"></span> <span translate>BARCODE.SCAN_BARCODE</span>
</a>
</li>
Expand Down
30 changes: 28 additions & 2 deletions client/src/modules/stock/lots/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ angular.module('bhima.controllers')
StockLotsController.$inject = [
'StockService', 'NotifyService', 'uiGridConstants', 'StockModalService', 'LanguageService',
'GridGroupingService', 'GridStateService', 'GridColumnService', '$state', '$httpParamSerializer',
'BarcodeService', 'LotService', 'LotsRegistryService', 'moment', 'bhConstants',
'BarcodeService', 'LotsRegistryService', 'moment', 'bhConstants', 'ReceiptModal',
];

/**
Expand All @@ -14,7 +14,7 @@ StockLotsController.$inject = [
function StockLotsController(
Stock, Notify, uiGridConstants, Modal, Languages,
Grouping, GridState, Columns, $state, $httpParamSerializer,
Barcode, LotService, LotsRegistry, moment, bhConstants,
Barcode, LotsRegistry, moment, bhConstants, Receipts,
) {
const vm = this;
const cacheKey = 'lot-grid';
Expand All @@ -28,6 +28,12 @@ function StockLotsController(
// barcode scanner
vm.openBarcodeScanner = openBarcodeScanner;

// barcode scanner
vm.openLotBarcodeScanner = openLotBarcodeScanner;

// show lot barcode
vm.openLotBarcodeModal = openLotBarcodeModal;

// options for the UI grid
vm.gridOptions = {
appScopeProvider : vm,
Expand Down Expand Up @@ -295,5 +301,25 @@ function StockLotsController(
});
}

function openLotBarcodeScanner() {
Barcode.modal({ shouldSearch : false })
.then(record => {
stockLotFilters.replaceFilters([
{ key : 'barcode', value : record.uuid, displayValue : record.uuid },
]);

load(stockLotFilters.formatHTTP(true));
vm.latestViewFilters = stockLotFilters.formatView();
});
}

/**
* @description display the barcode of the lot in a modal
* @param {string} uuid the lot uuid
*/
function openLotBarcodeModal(uuid) {
return Receipts.lotBarcodeReceipt(uuid);
}

startup();
}
6 changes: 6 additions & 0 deletions client/src/modules/stock/lots/registry.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ function LotsRegistryService(uiGridConstants, Session) {
displayName : 'STOCK.LOT',
headerTooltip : 'STOCK.LOT',
headerCellFilter : 'translate',
}, {
field : 'barcode',
displayName : 'BARCODE.BARCODE',
headerTooltip : 'BARCODE.BARCODE',
headerCellFilter : 'translate',
visible : false,
}, {
field : 'lot_description',
displayName : 'FORM.LABELS.DESCRIPTION',
Expand Down
10 changes: 10 additions & 0 deletions client/src/modules/stock/lots/templates/action.cell.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
<ul data-action="{{ rowRenderIndex}}" class="dropdown-menu-right" bh-dropdown-menu-auto-dropup uib-dropdown-menu>
<li class="bh-dropdown-header">{{row.entity.label}} - {{row.entity.text}}</li>

<li role="separator" class="divider"></li>

<li>
<a data-method="lot-schedule" ng-click="grid.appScope.openLotBarcodeModal(row.entity.uuid)" href>
<i class="fa fa-barcode"></i> <span translate>BARCODE.BARCODE</span>
</a>
</li>

<li role="separator" class="divider"></li>

<li bh-has-permission="grid.appScope.bhConstants.actions.EDIT_LOT">
<a data-method="edit" ng-click="grid.appScope.openLotModal(row.entity.uuid)" href>
<i class="fa fa-edit"></i> <span translate>FORM.LABELS.EDIT</span>
Expand Down
1 change: 1 addition & 0 deletions server/config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,7 @@ exports.configure = function configure(app) {
app.get('/receipts/stock/assign/:uuid', stockReports.stockAssignReceipt);
app.get('/receipts/stock/requisition/:uuid', stockReports.stockRequisitionReceipt);
app.get('/receipts/stock/adjustment/:document_uuid', stockReports.stockAdjustmentReceipt);
app.get('/receipts/stock/lots/:uuid/barcode', stockReports.lotBarcodeReceipt);

// stock consumption API
app.get('/stock/consumptions/average/:periodId', stock.getStockConsumptionAverage);
Expand Down
15 changes: 12 additions & 3 deletions server/controllers/stock/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ function getLotFilters(parameters) {
filters.equals('trackingExpiration', 'tracking_expiration');
filters.equals('stock_requisition_uuid', 'stock_requisition_uuid', 'm');

// barcode
filters.custom(
'barcode',
`CONCAT('LT', LEFT(HEX(l.uuid), 8)) = ?`,
);

// filter on the underlying voucher t
filters.custom(
'voucherReference',
Expand Down Expand Up @@ -185,7 +191,7 @@ async function lookupLotByUuid(uid) {
* @param {object} parameters - A request query object
* @param {string} finalClauseParameter - An optional final clause (GROUP BY, HAVING, ...) to add to query built
*/
function getLots(sqlQuery, parameters, finalClause = '', orderBy) {
function getLots(sqlQuery, parameters, finalClause = '', orderBy = '') {
const sql = sqlQuery || `
SELECT
BUID(l.uuid) AS uuid, l.label, l.unit_cost, l.expiration_date,
Expand Down Expand Up @@ -265,7 +271,8 @@ async function getLotsDepot(depotUuid, params, finalClause) {
m.date AS entry_date, i.purchase_interval, i.delay,
iu.text AS unit_type,
ig.name AS group_name, ig.tracking_expiration, ig.tracking_consumption,
dm.text AS documentReference, t.name AS tag_name, t.color, sv.wac
dm.text AS documentReference, t.name AS tag_name, t.color, sv.wac,
CONCAT('LT', LEFT(HEX(l.uuid), 8)) AS barcode
FROM stock_movement m
JOIN lot l ON l.uuid = m.lot_uuid
JOIN inventory i ON i.uuid = l.inventory_uuid
Expand Down Expand Up @@ -892,7 +899,7 @@ function computeLotIndicators(inventories) {
}

lot.exhausted = lot.quantity <= 0;
lot.expired = !lot.exhausted && (lot.expiration_date < today);
lot.expired = !lot.exhausted && (lot.expiration_date < today && lot.tracking_expiration);

// algorithm for tracking the stock consumption by day
if (lot.tracking_consumption && !lot.exhausted && !lot.expired) {
Expand Down Expand Up @@ -950,6 +957,8 @@ function computeLotIndicators(inventories) {
lot.at_risk_of_stock_out = !lot.expired
&& (lot.status === 'minimum_reached' || lot.status === 'security_reached');

lot.near_expiration = !!(lot.near_expiration && lot.tracking_expiration);

flattenLots.push(lot);
});
});
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/stock/reports/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const STOCK_ASSIGN_TEMPLATE = `${BASE_PATH}/stock/assignment/stock_assign.receip
const STOCK_ASSIGN_REGISTRY_TEMPLATE = `${BASE_PATH}/stock/assignment/stock_assign.registry.handlebars`;
const STOCK_CONSUMPTION_GRAPTH_TEMPLATE = `${BASE_PATH}/stock_consumption_graph.handlebars`;
const STOCK_MOVEMENT_REPORT_TEMPLATE = `${BASE_PATH}/stock_movement_report.handlebars`;
const LOT_BARCODE_TEMPLATE = `${BASE_PATH}/stock/lot_barcode/lot_barcode.handlebars`;

const STOCK_ENTRY_DEPOT_TEMPLATE = `${BASE_PATH}/stock_entry_depot.receipt.handlebars`;
const STOCK_ENTRY_PURCHASE_TEMPLATE = `${BASE_PATH}/stock_entry_purchase.receipt.handlebars`;
Expand Down Expand Up @@ -224,6 +225,7 @@ module.exports = {
STOCK_ENTRY_REPORT_TEMPLATE,
STOCK_LOST_STOCK_REPORT_TEMPLATE,
STOCK_LOTS_REPORT_TEMPLATE,
LOT_BARCODE_TEMPLATE,
STOCK_MOVEMENTS_REPORT_TEMPLATE,
STOCK_INLINE_MOVEMENTS_REPORT_TEMPLATE,
STOCK_SHEET_REPORT_TEMPLATE,
Expand Down
2 changes: 2 additions & 0 deletions server/controllers/stock/reports/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const stockAssignReceipt = require('./stock/assignment/stock_assign.receipt');
const stockAssignReport = require('./stock/assignment/stock_assign.registry');
const stockRequisitionReceipt = require('../requisition/requisition.receipt');
const stockChangesReport = require('./stock/stock_changes/stock_changes');
const lotBarcodeReceipt = require('./stock/lot_barcode/lot_barcode');

/**
* @function determineReceiptType
Expand Down Expand Up @@ -162,6 +163,7 @@ exports.purchaseOrderAnalysis = require('./purchase_order_analysis');

exports.purchasePrices = require('./purchase_prices');

exports.lotBarcodeReceipt = lotBarcodeReceipt;
exports.lostStockReport = lostStockReport;
exports.stockChangesReport = stockChangesReport;
exports.stockAdjustmentReceipt = stockAdjustmentReceipt;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{> head title="LOTS.BARCODE_FOR_LOT" }}

<!-- body -->
<div class="text-center">
{{#if metadata.enterprise.settings.enable_barcodes}}
<small>{{ details.inventory_text }} - {{ details.label }}</small><br>
<span>{{> barcode value=barcode}}</span><br>
<small><strong>{{ barcode }}</strong></small>

<script>JsBarcode('.barcode').init();</script>
{{/if}}
</div>
51 changes: 51 additions & 0 deletions server/controllers/stock/reports/stock/lot_barcode/lot_barcode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const {
_, ReportManager, db, identifiers, barcode, LOT_BARCODE_TEMPLATE,
} = require('../../common');

/**
* @method lotBarcodeReceipt
*
* @description
* This method displays the lot barcode
*
* GET /receipts/stock/lots/:uuid/barcode
*/
function lotBarcodeReceipt(req, res, next) {
let report;
const data = {};
const uuid = db.bid(req.params.uuid);
const options = {
filename : 'LOTS.BARCODE_FOR_LOT',
pageSize : 'A6',
orientation : 'landscape',
};
const optionReport = _.extend(req.query, options);

try {
report = new ReportManager(LOT_BARCODE_TEMPLATE, req.session, optionReport);
} catch (e) {
return next(e);
}

const sql = `
SELECT BUID(l.uuid) AS uuid, l.label, i.code, i.text AS inventory_text
FROM lot l
JOIN inventory i ON i.uuid = l.inventory_uuid
WHERE l.uuid = ?;
`;

return db.one(sql, [db.bid(uuid)])
.then(details => {
const { key } = identifiers.LOT;
data.details = details;
data.barcode = barcode.generate(key, details.uuid);
return report.render(data);
})
.then((result) => {
res.set(result.headers).send(result.report);
})
.catch(next)
.done();
}

module.exports = lotBarcodeReceipt;
3 changes: 3 additions & 0 deletions server/models/migrations/next/migrate.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ UPDATE report SET `report_key` = 'analysis_auxiliary_cashbox', `title_key` = 'RE
UPDATE unit SET
`name` = 'Analysis of Cashbox', `key` = 'REPORT.ANALYSIS_AUX_CASHBOX.TITLE', `description` = 'Analysis of auxiliary cashbox', `path` = '/reports/analysis_auxiliary_cashbox'
WHERE path = '/reports/analysis_auxiliary_cashboxes';

-- regenerate barcodes for lots
UPDATE lot SET barcode = CONCAT('LT', LEFT(HEX(lot.uuid), 8));

0 comments on commit 3a69ccb

Please sign in to comment.