summaryrefslogtreecommitdiff
path: root/import
diff options
context:
space:
mode:
authorLester Caine <lester@lsces.co.uk>2026-05-27 17:45:10 +0100
committerLester Caine <lester@lsces.co.uk>2026-05-27 17:45:10 +0100
commit6c360a42b7f45078c9256cbbc48d2aa8741e57ea (patch)
tree2c2b341af2adba73a9b4c58709ab70012e1db6b1 /import
parentb334d4bf4168012d1f4c7c580ee317cb439648b1 (diff)
downloadstock-6c360a42b7f45078c9256cbbc48d2aa8741e57ea.tar.gz
stock-6c360a42b7f45078c9256cbbc48d2aa8741e57ea.tar.bz2
stock-6c360a42b7f45078c9256cbbc48d2aa8741e57ea.zip
Add initial stock load importer and improve import results template
load_stock.php creates a pending StockMovement IN from a 3-column CSV (component_title, desc[ignored], qty), then ?process=y commits via processMovement(). import_results.tpl now shows movement status and the ?process=y hint when a pending movement is waiting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'import')
-rw-r--r--import/load_stock.php103
1 files changed, 103 insertions, 0 deletions
diff --git a/import/load_stock.php b/import/load_stock.php
new file mode 100644
index 0000000..d8bd2e6
--- /dev/null
+++ b/import/load_stock.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Load initial stock from a 3-column CSV (component_title, description[ignored], quantity).
+ * No header row. Creates one IN movement and adds each row as an item.
+ *
+ * Place your CSV at: stock/import/data/stock.csv
+ * Browse to this page to create/reload the movement in draft status.
+ * Append ?process=y to commit stock levels and mark the movement complete.
+ *
+ * @package stock
+ */
+
+namespace Bitweaver\Stock;
+
+require_once '../../kernel/includes/setup_inc.php';
+
+global $gBitSystem, $gBitSmarty, $gBitDb;
+
+$gBitSystem->verifyPackage( 'stock' );
+$gBitSystem->verifyPermission( 'p_stock_admin' );
+
+require_once STOCK_PKG_CLASS_PATH.'StockMovement.php';
+
+$csvFile = __DIR__.'/data/stock.csv';
+$doProcess = ( ( $_REQUEST['process'] ?? '' ) === 'y' );
+$loaded = 0;
+$skipped = 0;
+$errors = [];
+$movement = null;
+
+if( !file_exists( $csvFile ) ) {
+ $errors[] = 'CSV file not found: '.$csvFile;
+} else {
+ $handle = fopen( $csvFile, 'r' );
+ if( $handle === false ) {
+ $errors[] = 'Cannot open CSV file.';
+ } else {
+ $rows = [];
+ while( ( $data = fgetcsv( $handle, 1000, ',', '"', '' ) ) !== false ) {
+ $rows[] = $data;
+ }
+ fclose( $handle );
+
+ // Create the movement
+ $movement = new StockMovement();
+ $pHash = [
+ 'title' => 'Initial Stock Load',
+ 'direction' => STOCK_MOVEMENT_IN,
+ 'status' => 'pending',
+ ];
+ if( !$movement->store( $pHash ) ) {
+ $errors[] = 'Failed to create stock movement.';
+ } else {
+ foreach( $rows as $rowNum => $data ) {
+ $componentTitle = trim( $data[0] ?? '' );
+ $qty = isset( $data[2] ) && is_numeric( trim( $data[2] ) ) ? (float)trim( $data[2] ) : null;
+
+ if( empty( $componentTitle ) ) {
+ $skipped++;
+ $errors[] = "Row ".($rowNum+1).": empty title, skipped.";
+ continue;
+ }
+ if( $qty === null || $qty <= 0 ) {
+ $skipped++;
+ $errors[] = "Row ".($rowNum+1).": '$componentTitle' — invalid quantity, skipped.";
+ continue;
+ }
+
+ $contentId = $gBitDb->getOne(
+ "SELECT sc.`content_id`
+ FROM `".BIT_DB_PREFIX."stock_component` sc
+ INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON lc.`content_id` = sc.`content_id`
+ WHERE lc.`title` = ?",
+ [ $componentTitle ]
+ );
+ if( !$contentId ) {
+ $skipped++;
+ $errors[] = "Row ".($rowNum+1).": component '$componentTitle' not found, skipped.";
+ continue;
+ }
+
+ $movement->addItem( (int)$contentId, $qty, 'SGL' );
+ $loaded++;
+ }
+
+ if( $doProcess && $loaded > 0 ) {
+ if( !$movement->processMovement() ) {
+ $errors[] = 'processMovement() failed: '.implode( ', ', $movement->mErrors );
+ }
+ }
+ }
+ }
+}
+
+$gBitSmarty->assign( 'loaded', $loaded );
+$gBitSmarty->assign( 'skipped', $skipped );
+$gBitSmarty->assign( 'deleted', 0 );
+$gBitSmarty->assign( 'errors', $errors );
+$gBitSmarty->assign( 'csvFile', $csvFile );
+$gBitSmarty->assign( 'movement', $movement );
+$gBitSmarty->assign( 'doProcess', $doProcess );
+
+$gBitSystem->display( 'bitpackage:stock/import_results.tpl', 'Import Stock' );