Skip to content

Commit 78827cd

Browse files
authored
Merge pull request #28 from Invertus/BRD-370/variant-prices
[WIP] BRD-370: variant update SDK
2 parents fb638c6 + bf70d26 commit 78827cd

File tree

3 files changed

+166
-33
lines changed

3 files changed

+166
-33
lines changed

src/Adapters/PrestaShopAdapter.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,29 @@ private function transformVariants(array &$result, array $variants): void
191191
$transformedVariant = [
192192
'id' => (string) $variant['remoteId'],
193193
'sku' => $variant['sku'] ?? '',
194-
'url' => $this->getLocaleSpecificUrl($variant['productUrl']['localizedValues'] ?? [], $locale),
194+
'productUrl' => $this->getLocaleSpecificUrl($variant['productUrl']['localizedValues'] ?? [], $locale),
195195
'attributes' => $this->transformVariantAttributesForLocale($variant['attributes'] ?? [], $locale)
196196
];
197197

198+
// Add variant-level prices if available
199+
if (isset($variant['price'])) {
200+
$transformedVariant['price'] = $variant['price'];
201+
}
202+
if (isset($variant['basePrice'])) {
203+
$transformedVariant['basePrice'] = $variant['basePrice'];
204+
}
205+
if (isset($variant['priceTaxExcluded'])) {
206+
$transformedVariant['priceTaxExcluded'] = $variant['priceTaxExcluded'];
207+
}
208+
if (isset($variant['basePriceTaxExcluded'])) {
209+
$transformedVariant['basePriceTaxExcluded'] = $variant['basePriceTaxExcluded'];
210+
}
211+
212+
// Add variant-level imageUrl if available
213+
if (isset($variant['imageUrl']) && is_array($variant['imageUrl'])) {
214+
$transformedVariant['imageUrl'] = $this->transformImageUrl($variant['imageUrl']);
215+
}
216+
198217
if ($locale === 'en-US') {
199218
$variantsByLocale['variants'][] = $transformedVariant;
200219
} else {

src/Validators/DataValidator.php

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ public function validateProduct(array $product): void
4040
$errors = array_merge($errors, $fieldErrors);
4141
}
4242

43+
// Validate localized variant fields (e.g., variants_lt-LT, variants_lv-LV)
44+
if (isset($this->fieldConfiguration['variants'])) {
45+
$variantsConfig = $this->fieldConfiguration['variants'];
46+
foreach ($product as $fieldName => $value) {
47+
// Check if this is a localized variants field that wasn't already validated
48+
if (str_starts_with($fieldName, 'variants_') && !isset($this->fieldConfiguration[$fieldName])) {
49+
$fieldErrors = $this->validateField($fieldName, $value, $variantsConfig);
50+
$errors = array_merge($errors, $fieldErrors);
51+
}
52+
}
53+
}
54+
4355
if (!empty($errors)) {
4456
throw new ValidationException('Product validation failed', $errors);
4557
}
@@ -205,8 +217,8 @@ private function validateVariants(string $fieldName, array $variants, FieldConfi
205217
continue;
206218
}
207219

208-
// Validate required variant fields (based on Go ProductVariant struct)
209-
$requiredFields = ['id', 'sku', 'url', 'attributes'];
220+
// Validate required variant fields
221+
$requiredFields = ['id', 'sku', 'productUrl', 'attributes'];
210222
foreach ($requiredFields as $requiredField) {
211223
if (!isset($variant[$requiredField])) {
212224
$errors[] = "Field '{$fieldName}' variant at index {$index} must have '{$requiredField}' field";
@@ -219,44 +231,41 @@ private function validateVariants(string $fieldName, array $variants, FieldConfi
219231
$errors[] = "Field '{$fieldName}' variant at index {$index} 'id' must be a non-empty string";
220232
}
221233

222-
if (!is_string($variant['url']) || !filter_var($variant['url'], FILTER_VALIDATE_URL)) {
223-
$errors[] = "Field '{$fieldName}' variant at index {$index} 'url' must be a valid URL";
234+
if (!is_string($variant['productUrl']) || !filter_var($variant['productUrl'], FILTER_VALIDATE_URL)) {
235+
$errors[] = "Field '{$fieldName}' variant at index {$index} 'productUrl' must be a valid URL";
224236
}
225237

226238
if (!is_array($variant['attributes'])) {
227239
$errors[] = "Field '{$fieldName}' variant at index {$index} 'attributes' must be an array";
228240
continue;
229241
}
230242

231-
// Validate variant attributes against field config attributes
232-
if ($fieldConfig->attributes !== null) {
233-
foreach ($fieldConfig->attributes as $attrName => $attrConfig) {
234-
if (isset($variant['attributes'][$attrName])) {
235-
$attribute = $variant['attributes'][$attrName];
236-
237-
// Validate the attribute structure (must have 'name' and 'value')
238-
if (!is_array($attribute)) {
239-
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute '{$attrName}' must be an object with 'name' and 'value' fields";
240-
continue;
241-
}
243+
// Validate variant attributes structure - expecting array of objects with 'name' and 'value'
244+
foreach ($variant['attributes'] as $attrIndex => $attribute) {
245+
if (!is_array($attribute)) {
246+
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute at index {$attrIndex} must be an object with 'name' and 'value' fields";
247+
continue;
248+
}
242249

243-
if (!isset($attribute['name']) || !isset($attribute['value'])) {
244-
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute '{$attrName}' must have 'name' and 'value' fields";
245-
continue;
246-
}
250+
if (!isset($attribute['name']) || !isset($attribute['value'])) {
251+
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute at index {$attrIndex} must have 'name' and 'value' fields";
252+
continue;
253+
}
247254

248-
if (!is_string($attribute['name']) || $attribute['name'] !== $attrName) {
249-
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute '{$attrName}' name field must match the attribute key";
250-
}
255+
if (!is_string($attribute['name']) || empty($attribute['name'])) {
256+
$errors[] = "Field '{$fieldName}' variant at index {$index} attribute at index {$attrIndex} 'name' must be a non-empty string";
257+
continue;
258+
}
251259

252-
// Validate the attribute value against the field config
253-
$attrErrors = $this->validateField(
254-
"{$fieldName}.variants[{$index}].attributes.{$attrName}.value",
255-
$attribute['value'],
256-
$attrConfig
257-
);
258-
$errors = array_merge($errors, $attrErrors);
259-
}
260+
// Validate the attribute value against the field config if available
261+
if ($fieldConfig->attributes !== null && isset($fieldConfig->attributes[$attribute['name']])) {
262+
$attrConfig = $fieldConfig->attributes[$attribute['name']];
263+
$attrErrors = $this->validateField(
264+
"{$fieldName}.variants[{$index}].attributes[{$attrIndex}].value",
265+
$attribute['value'],
266+
$attrConfig
267+
);
268+
$errors = array_merge($errors, $attrErrors);
260269
}
261270
}
262271
}

tests/Adapters/PrestaShopAdapterTest.php

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ public function testTransformProductWithVariants(): void
400400
$variant1 = $product['variants'][0];
401401
$this->assertEquals('26911', $variant1['id']);
402402
$this->assertEquals('M0E20000000EAAK-34', $variant1['sku']);
403-
$this->assertEquals('http://prestashop/sneakers/1807-26911-sneakers.html', $variant1['url']);
403+
$this->assertEquals('http://prestashop/sneakers/1807-26911-sneakers.html', $variant1['productUrl']);
404404
$this->assertEquals([
405405
[
406406
'name' => 'size',
@@ -416,7 +416,7 @@ public function testTransformProductWithVariants(): void
416416
$variant2 = $product['variants'][1];
417417
$this->assertEquals('26912', $variant2['id']);
418418
$this->assertEquals('M0E20000000EAAL', $variant2['sku']);
419-
$this->assertEquals('http://prestashop/sneakers/1807-26912-sneakers.html', $variant2['url']);
419+
$this->assertEquals('http://prestashop/sneakers/1807-26912-sneakers.html', $variant2['productUrl']);
420420
$this->assertEquals([
421421
[
422422
'name' => 'size',
@@ -1189,4 +1189,109 @@ public function testTransformWithInvalidVariantsTypes(): void
11891189
$this->assertCount(1, $result["products"]);
11901190
$this->assertEmpty($this->getProductFromResult($result)['variants']); // All variants invalid or filtered out
11911191
}
1192+
1193+
public function testTransformVariantWithPricesAndImageUrl(): void
1194+
{
1195+
$prestaShopData = [
1196+
'products' => [
1197+
[
1198+
'remoteId' => '3642',
1199+
'sku' => 'V-L558',
1200+
'price' => '10.00',
1201+
'basePrice' => '12.00',
1202+
'priceTaxExcluded' => '8.50',
1203+
'basePriceTaxExcluded' => '10.00',
1204+
'localizedNames' => [
1205+
'en-US' => 'Drip tray'
1206+
],
1207+
'categories' => [],
1208+
'variants' => [
1209+
[
1210+
'remoteId' => 1,
1211+
'sku' => 'ABCD1',
1212+
'price' => 0,
1213+
'basePrice' => '0.00',
1214+
'priceTaxExcluded' => '0.00',
1215+
'basePriceTaxExcluded' => '0.00',
1216+
'attributes' => [
1217+
'Pusė' => [
1218+
'localizedNames' => [
1219+
'en-US' => 'Side'
1220+
],
1221+
'localizedValues' => [
1222+
'en-US' => 'right'
1223+
]
1224+
]
1225+
],
1226+
'productUrl' => [
1227+
'localizedValues' => [
1228+
'en-US' => 'http://prestashop/en/3642-1-drip-tray.html'
1229+
]
1230+
],
1231+
'imageUrl' => [
1232+
'small' => 'http://prestashop/13600-square_cart_default/drip-tray.jpg',
1233+
'medium' => 'http://prestashop/13600-home_default/drip-tray.jpg'
1234+
]
1235+
],
1236+
[
1237+
'remoteId' => 2,
1238+
'sku' => 'ABCD-333',
1239+
'price' => 15.99,
1240+
'basePrice' => '18.00',
1241+
'priceTaxExcluded' => '13.50',
1242+
'basePriceTaxExcluded' => '15.00',
1243+
'attributes' => [
1244+
'Pusė' => [
1245+
'localizedNames' => [
1246+
'en-US' => 'Side'
1247+
],
1248+
'localizedValues' => [
1249+
'en-US' => 'left'
1250+
]
1251+
]
1252+
],
1253+
'productUrl' => [
1254+
'localizedValues' => [
1255+
'en-US' => 'http://prestashop/en/3642-2-drip-tray.html'
1256+
]
1257+
],
1258+
'imageUrl' => [
1259+
'small' => 'http://prestashop/13601-square_cart_default/drip-tray.jpg',
1260+
'medium' => 'http://prestashop/13601-home_default/drip-tray.jpg'
1261+
]
1262+
]
1263+
]
1264+
]
1265+
]
1266+
];
1267+
1268+
$result = $this->adapter->transform($prestaShopData);
1269+
$product = $this->getProductFromResult($result);
1270+
1271+
$this->assertCount(2, $product['variants']);
1272+
1273+
// First variant - check prices and imageUrl
1274+
$variant1 = $product['variants'][0];
1275+
$this->assertEquals('1', $variant1['id']);
1276+
$this->assertEquals('ABCD1', $variant1['sku']);
1277+
$this->assertEquals(0, $variant1['price']);
1278+
$this->assertEquals('0.00', $variant1['basePrice']);
1279+
$this->assertEquals('0.00', $variant1['priceTaxExcluded']);
1280+
$this->assertEquals('0.00', $variant1['basePriceTaxExcluded']);
1281+
$this->assertArrayHasKey('imageUrl', $variant1);
1282+
$this->assertEquals('http://prestashop/13600-square_cart_default/drip-tray.jpg', $variant1['imageUrl']['small']);
1283+
$this->assertEquals('http://prestashop/13600-home_default/drip-tray.jpg', $variant1['imageUrl']['medium']);
1284+
1285+
// Second variant - check prices and imageUrl
1286+
$variant2 = $product['variants'][1];
1287+
$this->assertEquals('2', $variant2['id']);
1288+
$this->assertEquals('ABCD-333', $variant2['sku']);
1289+
$this->assertEquals(15.99, $variant2['price']);
1290+
$this->assertEquals('18.00', $variant2['basePrice']);
1291+
$this->assertEquals('13.50', $variant2['priceTaxExcluded']);
1292+
$this->assertEquals('15.00', $variant2['basePriceTaxExcluded']);
1293+
$this->assertArrayHasKey('imageUrl', $variant2);
1294+
$this->assertEquals('http://prestashop/13601-square_cart_default/drip-tray.jpg', $variant2['imageUrl']['small']);
1295+
$this->assertEquals('http://prestashop/13601-home_default/drip-tray.jpg', $variant2['imageUrl']['medium']);
1296+
}
11921297
}

0 commit comments

Comments
 (0)