@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
/** Computes a form's total price as the sum of its elements' prices. */
|
||||
/** Computes a form's total price as the sum of its elements' prices, reduced by membership discount. */
|
||||
class RsvFormPriceCalculator {
|
||||
public function calculate(RsvFormDefinition $definition, RsvFormData $data): float {
|
||||
global $rsv_form_price_registry;
|
||||
@@ -16,6 +16,7 @@ class RsvFormPriceCalculator {
|
||||
$total += (float) $calculator($element, $data->getValue($element->getName()));
|
||||
}
|
||||
|
||||
return $total;
|
||||
$pct = (new RsvMembershipService())->discount_for($definition, $data);
|
||||
return $total * (1.0 - max(0.0, min(100.0, $pct)) / 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,25 @@
|
||||
final class RsvFormCalculatedValues {
|
||||
/** @return array<string, mixed> */
|
||||
public function for(RsvFormDefinition $definition, RsvFormData $data): array {
|
||||
$calculator = new RsvFormPriceCalculator();
|
||||
global $rsv_form_price_registry;
|
||||
|
||||
$price_before_discount = 0.0;
|
||||
foreach ($definition->getElements() as $element) {
|
||||
$element_calculator = $rsv_form_price_registry->get($element->getType());
|
||||
if ($element_calculator === null) {
|
||||
continue;
|
||||
}
|
||||
$price_before_discount += (float) $element_calculator($element, $data->getValue($element->getName()));
|
||||
}
|
||||
|
||||
$discount_pct = (new RsvMembershipService())->discount_for($definition, $data);
|
||||
$final_price = $calculator->calculate($definition, $data);
|
||||
|
||||
return [
|
||||
'price' => (new RsvFormPriceCalculator())->calculate($definition, $data),
|
||||
'price' => $final_price,
|
||||
'price_before_discount' => $price_before_discount,
|
||||
'discount_percent' => $discount_pct,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -14,6 +31,6 @@ final class RsvFormCalculatedValues {
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function names(): array {
|
||||
return ['price'];
|
||||
return ['price', 'price_before_discount', 'discount_percent'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ class RsvFormDefinition {
|
||||
|
||||
public string $email_key = "";
|
||||
|
||||
public array $membership = [];
|
||||
|
||||
public string $success_message = "";
|
||||
|
||||
/**
|
||||
* @param array<int,mixed> $definition Full definition array including 'elements', 'email_key' and 'success_message'.
|
||||
* @param array<string,mixed> $definition Full definition array including 'elements', 'email_key' and 'success_message'.
|
||||
*/
|
||||
public function __construct(string $id, array $definition) {
|
||||
$this->_elements = [];
|
||||
@@ -23,6 +25,7 @@ class RsvFormDefinition {
|
||||
|
||||
$this->_id = $id;
|
||||
$this->email_key = $definition['email_key'] ?? '';
|
||||
$this->membership = $definition['membership'] ?? [];
|
||||
$this->success_message = $definition['success_message'] ?? '';
|
||||
}
|
||||
|
||||
@@ -34,6 +37,15 @@ class RsvFormDefinition {
|
||||
return $this->email_key;
|
||||
}
|
||||
|
||||
/** @return array<int,array{program_id:int,discount:float,field:string}> */
|
||||
public function getMembershipBindings(): array {
|
||||
return $this->membership['bindings'] ?? [];
|
||||
}
|
||||
|
||||
public function getMembershipCombine(): string {
|
||||
return $this->membership['combine'] ?? 'max';
|
||||
}
|
||||
|
||||
/** Template shown to the visitor after a successful submission. */
|
||||
public function getSuccessMessage(): string {
|
||||
return $this->success_message;
|
||||
|
||||
@@ -34,6 +34,9 @@ final class RsvFormDefinitionValidator {
|
||||
$errors[] = 'Form must contain a submit button.';
|
||||
}
|
||||
|
||||
// Validate membership bindings if present.
|
||||
$errors = array_merge($errors, $this->validate_membership_bindings($definition));
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
@@ -109,4 +112,41 @@ final class RsvFormDefinitionValidator {
|
||||
global $rsv_template_registry;
|
||||
return new RsvTemplateEngine(registry: $rsv_template_registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $definition
|
||||
* @return list<string>
|
||||
*/
|
||||
private function validate_membership_bindings(array $definition): array {
|
||||
$errors = [];
|
||||
$membership = $definition['membership'] ?? [];
|
||||
|
||||
if (!is_array($membership)) {
|
||||
return $errors;
|
||||
}
|
||||
|
||||
$bindings = $membership['bindings'] ?? [];
|
||||
if (!is_array($bindings)) {
|
||||
return $errors;
|
||||
}
|
||||
|
||||
foreach ($bindings as $idx => $binding) {
|
||||
if (!is_array($binding)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$program_id = intval($binding['program_id'] ?? 0);
|
||||
$discount = floatval($binding['discount'] ?? 0.0);
|
||||
|
||||
if ($program_id <= 0) {
|
||||
$errors[] = "Membership binding {$idx}: program_id must be a positive integer.";
|
||||
}
|
||||
|
||||
if ($discount < 0.0 || $discount > 100.0) {
|
||||
$errors[] = "Membership binding {$idx}: discount must be between 0 and 100.";
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user