implement TwingleShop integration

This commit is contained in:
Marc Michalsky 2024-03-21 11:53:57 +01:00 committed by Jens Schuppe
parent ea46e6a747
commit 8cfa270dff
60 changed files with 5200 additions and 106 deletions

View file

@ -17,6 +17,8 @@ declare(strict_types = 1);
use CRM_Twingle_ExtensionUtil as E;
use Civi\Twingle\Exceptions\BaseException;
use Civi\Twingle\Shop\Exceptions\LineItemException;
use Civi\Twingle\Shop\BAO\TwingleProduct;
class CRM_Twingle_Submission {
@ -41,7 +43,18 @@ class CRM_Twingle_Submission {
public const EMPLOYER_RELATIONSHIP_TYPE_ID = 5;
/**
* @param array<string, mixed> &$params
* List of allowed product attributes.
*/
const ALLOWED_PRODUCT_ATTRIBUTES = [
'name',
'internal_id',
'price',
'count',
'total_value',
];
/**
* @param array &$params
* A reference to the parameters array of the submission.
*
* @param \CRM_Twingle_Profile $profile
@ -123,6 +136,22 @@ class CRM_Twingle_Submission {
}
}
// Validate products
if (!empty($params['products']) && $profile->isShopEnabled()) {
if (is_string($params['products'])) {
$products = json_decode($params['products'], TRUE);
$params['products'] = array_map(function ($product) {
return array_intersect_key($product, array_flip(self::ALLOWED_PRODUCT_ATTRIBUTES));
}, $products);
}
if (!is_array($params['products'])) {
throw new CiviCRM_API3_Exception(
E::ts('Invalid format for products.'),
'invalid_format'
);
}
}
// Validate campaign_id, if given.
if (isset($params['campaign_id'])) {
// Check whether campaign_id is a numeric string and cast it to an integer.
@ -433,4 +462,131 @@ class CRM_Twingle_Submission {
}
}
/**
* @param $values
* Processed data
* @param $submission
* Submission data
* @param $profile
* The twingle profile used
*
* @throws \CiviCRM_API3_Exception
* @throws \CRM_Core_Exception
* @throws \Civi\Twingle\Shop\Exceptions\LineItemException
*/
public static function createLineItems($values, $submission, $profile): array {
$line_items = [];
$sum_line_items = 0;
$contribution_id = $values['contribution']['id'];
if (empty($contribution_id)) {
throw new LineItemException(
"Could not find contribution id for line item assignment.",
LineItemException::ERROR_CODE_CONTRIBUTION_NOT_FOUND
);
}
foreach ($submission['products'] as $product) {
$line_item_data = [
'entity_table' => "civicrm_contribution",
'contribution_id' => $contribution_id,
'entity_id' => $contribution_id,
'label' => $product['name'],
'qty' => $product['count'],
'unit_price' => $product['price'],
'line_total' => $product['total_value'],
'sequential' => 1,
];
// Try to find the TwingleProduct with its corresponding PriceField
// for this product
try {
$price_field = TwingleProduct::findByExternalId($product['id']);
}
catch (Exception $e) {
Civi::log()->error(E::LONG_NAME .
": An error occurred when searching for TwingleShop with the external ID " .
$product['id'], ['exception' => $e]);
$price_field = NULL;
}
// 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']) {
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']]);
}
// Log warning if name differs from the submission
if ($price_field->name != $product['name']) {
Civi::log()->warning(E::LONG_NAME .
": Name for product " . $product['name'] . " differs from the PriceField " .
"Using the name from the submission.", ['price_field' => $price_field->name, 'submission' => $product['name']]);
}
// Set the financial type and price field id
$line_item_data['financial_type_id'] = $price_field->financial_type_id;
$line_item_data['price_field_value_id'] = $price_field->getPriceFieldValueId();
$line_item_data['price_field_id'] = $price_field->price_field_id;
$line_item_data['description'] = $price_field->description;
}
// If not found, use the shops default financial type
else {
$financial_type_id = $profile->getAttribute('shop_financial_type', 1);
$line_item_data['financial_type_id'] = $financial_type_id;
}
// Create the line item
$line_item = civicrm_api3('LineItem', 'create', $line_item_data);
if (!empty($line_item['is_error'])) {
$line_item_name = $line_item_data['name'];
throw new CiviCRM_API3_Exception(
E::ts("Could not create line item for product '$line_item_name'"),
'api_error'
);
}
$line_items[] = array_pop($line_item['values']);
$sum_line_items += $product['total_value'];
}
// Create line item for donation part
$donation_sum = (float) $values['contribution']['total_amount'] - $sum_line_items;
if ($donation_sum > 0) {
$donation_financial_type_id = $profile->getAttribute('shop_donation_financial_type', 1);
$donation_label = civicrm_api3('FinancialType', 'getsingle', [
'return' => ['name'],
'id' => $donation_financial_type_id,
])['name'];
$donation_line_item_data = [
'entity_table' => "civicrm_contribution",
'contribution_id' => $contribution_id,
'entity_id' => $contribution_id,
'label' => $donation_label,
'qty' => 1,
'unit_price' => $donation_sum,
'line_total' => $donation_sum,
'financial_type_id' => $donation_financial_type_id,
'sequential' => 1,
];
$donation_line_item = civicrm_api3('LineItem', 'create', $donation_line_item_data);
if (!empty($donation_line_item['is_error'])) {
throw new CiviCRM_API3_Exception(
E::ts("Could not create line item for donation"),
'api_error'
);
}
$line_items[] = array_pop($donation_line_item['values']);
}
return $line_items;
}
}