diff --git a/CRM/Twingle/Submission.php b/CRM/Twingle/Submission.php index 606a714..48c658a 100644 --- a/CRM/Twingle/Submission.php +++ b/CRM/Twingle/Submission.php @@ -46,6 +46,7 @@ class CRM_Twingle_Submission { * List of allowed product attributes. */ const ALLOWED_PRODUCT_ATTRIBUTES = [ + 'id', 'name', 'internal_id', 'price', @@ -513,8 +514,8 @@ class CRM_Twingle_Submission { // If found, use the financial type and price field id from the price field if ($price_field) { - // Log warning if price differs from the submission - if ($price_field->price != (int) $product['price']) { + // Log warning if price is not variable and differs from the submission + if ($price_field->price !== Null && $price_field->price != (int) $product['price']) { Civi::log()->warning(E::LONG_NAME . ": Price for product " . $product['name'] . " differs from the PriceField. " . "Using the price from the submission.", ['price_field' => $price_field->price, 'submission' => $product['price']]); diff --git a/Civi/Twingle/Shop/BAO/TwingleProduct.php b/Civi/Twingle/Shop/BAO/TwingleProduct.php index d6448b2..62f37c3 100644 --- a/Civi/Twingle/Shop/BAO/TwingleProduct.php +++ b/Civi/Twingle/Shop/BAO/TwingleProduct.php @@ -14,7 +14,7 @@ use CRM_Utils_Type; use function Civi\Twingle\Shop\Utils\convert_int_to_bool; use function Civi\Twingle\Shop\Utils\convert_str_to_date; use function Civi\Twingle\Shop\Utils\convert_str_to_int; -use function Civi\Twingle\Shop\Utils\convert_null_to_int; +use function Civi\Twingle\Shop\Utils\convert_empty_string_to_null; use function Civi\Twingle\Shop\Utils\filter_attributes; use function Civi\Twingle\Shop\Utils\validate_data_types; @@ -112,9 +112,9 @@ class TwingleProduct extends TwingleProductDAO { ]; /** - * Attributes that need to be converted from NULL to int. + * Empty string to null conversion. */ - protected const NULL_TO_INT_CONVERSION = [ + protected const EMPTY_STRING_TO_NULL = [ "price", ]; @@ -198,6 +198,28 @@ class TwingleProduct extends TwingleProductDAO { self::CAN_BE_ZERO, ); + // Does this product allow to enter a custom price? + $custom_price = array_key_exists('price', $product_data) && $product_data['price'] === Null; + if (!$custom_price && isset($product_data['price_field_id'])) { + try { + $price_field = civicrm_api3('PriceField', 'getsingle', [ + 'id' => $product_data['price_field_id'], + 'return' => 'is_enter_qty', + ]); + $custom_price = (bool) $price_field['is_enter_qty']; + } + catch (CRM_Core_Exception $e) { + throw new ProductException( + E::ts("Could not find PriceField for Twingle Product ['id': %1, 'external_id': %2]: %3", + [ + 1 => $product_data['id'], + 2 => $product_data['external_id'], + 3 => $e->getMessage(), + ]), + ProductException::ERROR_CODE_PRICE_FIELD_NOT_FOUND); + } + } + // Amend data from corresponding PriceFieldValue if (isset($product_data['price_field_id'])) { try { @@ -216,7 +238,7 @@ class TwingleProduct extends TwingleProductDAO { ProductException::ERROR_CODE_PRICE_FIELD_VALUE_NOT_FOUND); } $product_data['name'] = $product_data['name'] ?? $price_field_value['label']; - $product_data['price'] = $product_data['price'] ?? $price_field_value['amount']; + $product_data['price'] = $custom_price ? Null : $product_data['price'] ?? $price_field_value['amount']; $product_data['financial_type_id'] = $product_data['financial_type_id'] ?? $price_field_value['financial_type_id']; $product_data['is_active'] = $product_data['is_active'] ?? $price_field_value['is_active']; $product_data['sort'] = $product_data['sort'] ?? $price_field_value['weight']; @@ -228,7 +250,7 @@ class TwingleProduct extends TwingleProductDAO { convert_str_to_int($product_data, self::STR_TO_INT_CONVERSION); convert_int_to_bool($product_data, self::INT_TO_BOOL_CONVERSION); convert_str_to_date($product_data, self::STR_TO_DATE_CONVERSION); - convert_null_to_int($product_data, self::NULL_TO_INT_CONVERSION); + convert_empty_string_to_null($product_data, self::EMPTY_STRING_TO_NULL); } catch (\Exception $e) { throw new ProductException($e->getMessage(), ProductException::ERROR_CODE_ATTRIBUTE_WRONG_DATA_TYPE); @@ -308,6 +330,13 @@ class TwingleProduct extends TwingleProductDAO { 'html_type' => 'Text', 'is_required' => false, ]; + + // If the product has no fixed price, allow the user to enter a custom price + if ($this->price === Null) { + $price_field_data['is_enter_qty'] = true; + $price_field_data['is_display_amounts'] = false; + } + // Add id if in edit mode if ($mode == 'edit') { $price_field_data['id'] = $this->price_field_id; @@ -348,7 +377,7 @@ class TwingleProduct extends TwingleProductDAO { 'price_field_id' => $this->price_field_id, 'financial_type_id' => $this->financial_type_id, 'label' => $this->name, - 'amount' => $this->price, + 'amount' => $this->price === Null ? 1 : $this->price, 'is_active' => $this->is_active, 'description' => $this->description, ]; diff --git a/Civi/Twingle/Shop/Utils/TwingleShopUtils.php b/Civi/Twingle/Shop/Utils/TwingleShopUtils.php index 5ee45f7..0638615 100644 --- a/Civi/Twingle/Shop/Utils/TwingleShopUtils.php +++ b/Civi/Twingle/Shop/Utils/TwingleShopUtils.php @@ -45,7 +45,7 @@ function filter_attributes(array &$data, array $allowed_attributes, array $can_b function convert_str_to_int(array &$data, array $str_to_int_conversion): void { // Convert string to int foreach ($str_to_int_conversion as $attribute) { - if (isset($data[$attribute])) { + if (isset($data[$attribute]) && $data[$attribute] !== '') { try { $data[$attribute] = (int) $data[$attribute]; } catch (\Exception $e) { @@ -108,18 +108,17 @@ function convert_str_to_date(array &$data, array $str_to_date_conversion): void } /** - * Convert null to int + * Convert an empty string to null. * * @param array $data - * @param array $null_to_int_conversion + * @param array $empty_string_to_null * * @return void */ -function convert_null_to_int(array &$data, array $null_to_int_conversion): void { - // Convert null to int - foreach ($null_to_int_conversion as $attribute) { - if (array_key_exists($attribute, $data) && $data[$attribute] === NULL) { - $data[$attribute] = 0; +function convert_empty_string_to_null(array &$data, array $empty_string_to_null): void { + foreach ($empty_string_to_null as $attribute) { + if (isset($data[$attribute]) && $data[$attribute] === '') { + $data[$attribute] = NULL; } } }