summaryrefslogtreecommitdiff
path: root/import
diff options
context:
space:
mode:
authorLester Caine <lester@lsces.co.uk>2026-06-08 20:56:56 +0100
committerLester Caine <lester@lsces.co.uk>2026-06-08 20:56:56 +0100
commita838a2d3963738b2e9bc496b31e078ead79d4a43 (patch)
treebafe061903e4a076b92eb6d00813661f21f64ae8 /import
parent5e0af09c649b90a0963bd4e6b62f24b8cbf8edd9 (diff)
downloadstock-a838a2d3963738b2e9bc496b31e078ead79d4a43.tar.gz
stock-a838a2d3963738b2e9bc496b31e078ead79d4a43.tar.bz2
stock-a838a2d3963738b2e9bc496b31e078ead79d4a43.zip
stock: requisition system, movement BOM editor, autocomplete dropdowns
Requisitions: - add_requisition.php: create REQN movements linked to assemblies or kitlocker components; Ordered date stored on REQN xref start_date - ASSEMBLY xref group registered in schema (sort_order=1, template=assembly); ASSEMBLY item registered with multiple=1 for future multi-item reqns - StockMovement::loadXrefInfo() enriches assembly group rows with linked_title/linked_desc from liberty_content - view_xref_assembly_group/item templates: Assembly tab with qty, title link, type; Add item form on edit_movement for REQNs; hidden on I-direction - view_movement/edit_movement: isReqn flag hides assembly tab and type selector on ORDER/TRANS; add another assembly from edit_movement BOM editor: - stockmovement/view_xref_bom_group: Add component links to new add_movement_component.php instead of generic liberty/add_xref.php - add_movement_component.php/.tpl: movement-aware add component page; uses movement_lookup_inc, STOCKMOVEMENT_CONTENT_TYPE_GUID, sequential xorder, redirects back to edit_movement Autocomplete dropdowns (replace <select> everywhere): - add_requisition: hidden+text+dropdown widget; KLID in JSON for matching - add_supplier: AJAX contact lookup replaces static supplier list - list_stock: assembly selector replaced with autocomplete dropdown - edit_movement: From field proper dropdown replacing datalist; Movement Type radio fixed (was reading non-existent mInfo[reference]) - view_xref_assembly_group: Add item inline form with same widget Import: - ImportKitlockerAssemblies: upsert xrefs on reload; KLID/KLSGL/KL3M now stored on both assemblies and components (not assembly-only) - StockComponent::getList: kitlocker_only filter via EXISTS(KLID xref) list_movements: Add Requisition icon alongside Add Movement in header Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'import')
-rw-r--r--import/ImportKitlockerAssemblies.php110
1 files changed, 58 insertions, 52 deletions
diff --git a/import/ImportKitlockerAssemblies.php b/import/ImportKitlockerAssemblies.php
index aa96a1e..9c12200 100644
--- a/import/ImportKitlockerAssemblies.php
+++ b/import/ImportKitlockerAssemblies.php
@@ -4,19 +4,47 @@
*
* CSV column layout (0-based, header row skipped by loader):
* 0 Title MERG product code / designation (used as lc.title)
- * 1 KLID Kitlocker numeric ID code (stored as KLID xref on assemblies)
+ * 1 KLID Kitlocker numeric ID code (stored as KLID xref on both types)
* 2 Description Long description (stored as content body)
- * 3 KLSGL Kitlocker single-unit stock count (assemblies only → KLSGL xref)
- * 4 KL3M 3-month sales count (assemblies only → KL3M xref)
- * 5 Group Group number 1–28 → KLG01–KLG28 stgrp xref (both types)
+ * 3 KLSGL Kitlocker single-unit stock count (stored as KLSGL xref on both types)
+ * 4 KL3M 3-month sales count (stored as KL3M xref on both types)
+ * 5 Group Group number 1–99 → KLG01–KLG99 stgrp xref (both types)
* 6 Type 'A' = StockAssembly, 'C' = StockComponent
*
+ * On reload, existing records are not re-created but their kitlocker xrefs are upserted,
+ * so a fresh import run will tag components that were previously missing KLID etc.
+ *
* @package stock
*/
use Bitweaver\Stock\StockAssembly;
use Bitweaver\Stock\StockComponent;
+function stockKitlockerXrefUpsert( int $contentId, string $item, string $value ): void {
+ global $gBitDb;
+ $existingId = $gBitDb->getOne(
+ "SELECT `xref_id` FROM `".BIT_DB_PREFIX."liberty_xref`
+ WHERE `content_id` = ? AND `item` = ?",
+ [ $contentId, $item ]
+ );
+ if( $existingId ) {
+ $gBitDb->associateUpdate(
+ BIT_DB_PREFIX.'liberty_xref',
+ [ 'xkey' => substr( $value, 0, 32 ), 'last_update_date' => $gBitDb->NOW() ],
+ [ 'xref_id' => $existingId ]
+ );
+ } else {
+ $gBitDb->associateInsert( BIT_DB_PREFIX.'liberty_xref', [
+ 'xref_id' => $gBitDb->GenID( 'liberty_xref_seq' ),
+ 'content_id' => $contentId,
+ 'item' => $item,
+ 'xkey' => substr( $value, 0, 32 ),
+ 'xorder' => 0,
+ 'last_update_date' => $gBitDb->NOW(),
+ ] );
+ }
+}
+
function stockExpungeKitlockerItemByTitle( string $title, string $type ): bool {
global $gBitDb;
@@ -53,65 +81,43 @@ function stockImportKitlockerItem( array $data, int $rowNum ): array {
return $result;
}
- $guid = ( $type === 'A' ) ? 'stockassembly' : 'stockcomponent';
-
- $exists = $gBitDb->getOne(
- "SELECT lc.`content_id` FROM `".BIT_DB_PREFIX."liberty_content` lc
- WHERE lc.`content_type_guid` = ? AND lc.`title` = ?",
- [ $guid, $title ]
- );
- if( $exists ) {
- $result['skipped']++;
- $result['errors'][] = "Row $rowNum: '$title' already exists, skipped.";
- return $result;
- }
-
+ $guid = ( $type === 'A' ) ? 'stockassembly' : 'stockcomponent';
$klid = trim( $data[1] ?? '' );
$desc = trim( $data[2] ?? '' );
$klsgl = trim( $data[3] ?? '' );
$kl3m = trim( $data[4] ?? '' );
$group = (int)( $data[5] ?? 0 );
- $obj = ( $type === 'A' ) ? new StockAssembly() : new StockComponent();
- $pHash = [
- 'title' => $title,
- 'edit' => $desc,
- 'format_guid' => 'bithtml',
- ];
- if( !$obj->store( $pHash ) ) {
- $result['skipped']++;
- $result['errors'][] = "Row $rowNum: failed to store '$title'.";
- return $result;
- }
+ $contentId = (int)$gBitDb->getOne(
+ "SELECT lc.`content_id` FROM `".BIT_DB_PREFIX."liberty_content` lc
+ WHERE lc.`content_type_guid` = ? AND lc.`title` = ?",
+ [ $guid, $title ]
+ );
- $contentId = $obj->mContentId;
+ if( !$contentId ) {
+ $obj = ( $type === 'A' ) ? new StockAssembly() : new StockComponent();
+ $pHash = [
+ 'title' => $title,
+ 'edit' => $desc,
+ 'format_guid' => 'bithtml',
+ ];
+ if( !$obj->store( $pHash ) ) {
+ $result['skipped']++;
+ $result['errors'][] = "Row $rowNum: failed to store '$title'.";
+ return $result;
+ }
+ $contentId = $obj->mContentId;
+ }
- // Group tag — shared across both types via 'stock' package-level stgrp
+ // Group tag — both types
if( $group >= 1 && $group <= 99 ) {
- $xrefId = $gBitDb->GenID( 'liberty_xref_seq' );
- $gBitDb->associateInsert( BIT_DB_PREFIX.'liberty_xref', [
- 'xref_id' => $xrefId,
- 'content_id' => $contentId,
- 'item' => sprintf( 'KLG%02d', $group ),
- 'xorder' => 0,
- 'last_update_date' => $gBitDb->NOW(),
- ] );
+ stockKitlockerXrefUpsert( $contentId, sprintf( 'KLG%02d', $group ), '' );
}
- // Assembly-specific kitlocker xrefs
- if( $type === 'A' ) {
- foreach( [ 'KLID' => $klid, 'KLSGL' => $klsgl, 'KL3M' => $kl3m ] as $item => $value ) {
- if( $value !== '' ) {
- $xrefId = $gBitDb->GenID( 'liberty_xref_seq' );
- $gBitDb->associateInsert( BIT_DB_PREFIX.'liberty_xref', [
- 'xref_id' => $xrefId,
- 'content_id' => $contentId,
- 'item' => $item,
- 'xorder' => 0,
- 'xkey' => substr( $value, 0, 32 ),
- 'last_update_date' => $gBitDb->NOW(),
- ] );
- }
+ // Kitlocker xrefs — same set for assemblies and components
+ foreach( [ 'KLID' => $klid, 'KLSGL' => $klsgl, 'KL3M' => $kl3m ] as $item => $value ) {
+ if( $value !== '' ) {
+ stockKitlockerXrefUpsert( $contentId, $item, $value );
}
}