summaryrefslogtreecommitdiff
path: root/import/ImportSimpleComponent.php
blob: 1f8737571cbe6e688cf1385ff7cb7bbbbf2634a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<?php
/**
 * Simplified component CSV importer — title, description, supplier, PN, price.
 *
 * CSV column layout (0-based, header row skipped by loader):
 *   0  title          Component name
 *   1  description    Plain-text description (stored as bithtml content body)
 *   2  supplier       Supplier contact SCREF or title, case-insensitive (optional)
 *   3  supplier_pn    Supplier part number → xref #PN in xkey_ext (optional)
 *   4  supplier_price Supplier price       → xref #PR in xkey    (optional)
 *   5  supplier_url   Supplier URL         → xref #SUP data      (optional)
 *   6  qty_type       SGL/PCK/SHT/VOL — omit or blank for SGL    (optional)
 *   7  qty_value      Pack size for PCK (pieces per pack); dimensions for SHT (optional)
 *
 * Supplier name is matched against liberty_content.title for content_type_guid='contact'.
 * #SUP stores the contact content_id in the xref column; #PN and #PR share xorder=1
 * so they are grouped with the #SUP entry as one supplier set.
 *
 * Setting qty_type to PCK/SHT/VOL writes the appropriate xref on the component so that
 * movement CSV imports pick up the correct default qty type without a manual override.
 *
 * Existing components (matched by title) are skipped unless cleared first.
 *
 * @package stock
 */

use Bitweaver\Stock\StockComponent;

// Cache supplier lookups — only 4 or so suppliers in the CSV
$_stockSupplierCache = [];

function stockImportFindSupplier( string $name ): ?int {
	global $gBitDb, $_stockSupplierCache;

	$key = strtolower( trim( $name ) );
	if( array_key_exists( $key, $_stockSupplierCache ) ) {
		return $_stockSupplierCache[$key];
	}

	$contentId = $gBitDb->getOne(
		"SELECT `content_id` FROM `".BIT_DB_PREFIX."liberty_xref`
		 WHERE `item` = 'SCREF' AND UPPER( `xkey` ) = UPPER( ? )",
		[ trim( $name ) ]
	);

	$_stockSupplierCache[$key] = $contentId ? (int)$contentId : null;
	return $_stockSupplierCache[$key];
}

function stockExpungeComponentByTitle( string $title ): bool {
	global $gBitDb;

	$contentId = $gBitDb->getOne(
		"SELECT lc.`content_id`
		 FROM `".BIT_DB_PREFIX."liberty_content` lc
		 WHERE lc.`content_type_guid` = '".'stockcomponent'."' AND lc.`title` = ?",
		[ $title ]
	);
	if( !$contentId ) {
		return false;
	}

	$component = new StockComponent( (int)$contentId );
	$component->expunge();
	return true;
}

function stockImportSimpleComponent( array $data, int $rowNum ): array {
	global $gBitDb;

	$result = [ 'loaded' => 0, 'skipped' => 0, 'errors' => [] ];

	$title = trim( $data[0] ?? '' );
	if( empty( $title ) ) {
		$result['skipped']++;
		$result['errors'][] = "Row $rowNum: empty title, skipped.";
		return $result;
	}

	$exists = $gBitDb->getOne(
		"SELECT lc.`content_id`
		 FROM `".BIT_DB_PREFIX."liberty_content` lc
		 WHERE lc.`content_type_guid` = '".'stockcomponent'."' AND lc.`title` = ?",
		[ $title ]
	);
	if( $exists ) {
		$result['skipped']++;
		$result['errors'][] = "Row $rowNum: '$title' already exists, skipped.";
		return $result;
	}

	$description   = trim( $data[1] ?? '' );
	$supplierName  = trim( $data[2] ?? '' );
	$supplierPn    = trim( $data[3] ?? '' );
	$supplierPrice = trim( $data[4] ?? '' );
	$supplierUrl   = trim( $data[5] ?? '' );
	$qtyType       = strtoupper( trim( $data[6] ?? '' ) );
	$qtyValue      = trim( $data[7] ?? '' );

	$component = new StockComponent();
	$pHash = [
		'title'       => $title,
		'edit'        => $description,
		'format_guid' => 'bithtml',
	];
	if( !$component->store( $pHash ) ) {
		$result['skipped']++;
		$result['errors'][] = "Row $rowNum: failed to create component '$title'.";
		return $result;
	}

	$contentId = $component->mContentId;

	if( !empty( $supplierName ) ) {
		$supplierContentId = stockImportFindSupplier( $supplierName );
		if( !$supplierContentId ) {
			$result['errors'][] = "Row $rowNum: '$title' — supplier '$supplierName' not found in contacts, xrefs skipped.";
		} else {
			$xrefId = $gBitDb->GenID( 'liberty_xref_seq' );
			$gBitDb->associateInsert( BIT_DB_PREFIX.'liberty_xref', [
				'xref_id'          => $xrefId,
				'content_id'       => $contentId,
				'item'             => '#SUP',
				'xorder'           => 1,
				'xref'             => $supplierContentId,
				'xkey'             => substr( $supplierPn,    0, 32  ),
				'xkey_ext'         => substr( $supplierPrice, 0, 250 ),
				'data'             => $supplierUrl ?: null,
				'last_update_date' => $gBitDb->NOW(),
			] );
		}
	}

	// Quantity type xref — sets the default qty type used by movement CSV imports
	// and the pack size shown in BOM displays (PCK xref xkey = pieces per pack)
	if( in_array( $qtyType, [ 'PCK', 'SHT', 'VOL' ] ) ) {
		$gBitDb->associateInsert( BIT_DB_PREFIX.'liberty_xref', [
			'xref_id'          => $gBitDb->GenID( 'liberty_xref_seq' ),
			'content_id'       => $contentId,
			'item'             => $qtyType,
			'xkey'             => substr( $qtyValue, 0, 32 ),
			'xorder'           => 0,
			'last_update_date' => $gBitDb->NOW(),
		] );
	}

	$result['loaded']++;
	return $result;
}