Skip to content

Commit

Permalink
MAE-928: Apply discount when payment plan selected
Browse files Browse the repository at this point in the history
  • Loading branch information
asem-compuco committed Mar 17, 2023
1 parent 7174542 commit 3b44811
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 30 deletions.
5 changes: 4 additions & 1 deletion CRM/MembershipExtras/API/PaymentSchedule/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ protected function getInstalments(array $membershipTypes, array $nonMembershipPr
$joinDate = !empty($this->params['join_date']) ? new DateTime($this->params['join_date']) : NULL;
$startDate = !empty($this->params['start_date']) ? new DateTime($this->params['start_date']) : NULL;
$endDate = !empty($this->params['end_date']) ? new DateTime($this->params['end_date']) : NULL;
$totalAmount = !empty($this->params['total_amount']) ? $this->params['total_amount'] : NULL;
$membershipInstalmentsSchedule = new CRM_MembershipExtras_Service_MembershipInstalmentsSchedule(
$membershipTypes,
$this->params['schedule']
Expand All @@ -59,11 +60,13 @@ protected function getInstalments(array $membershipTypes, array $nonMembershipPr

$paymentMethod = $this->params['payment_method'];


return $membershipInstalmentsSchedule->generate(
$paymentMethod,
$membershipTypeDates['start_date'],
$membershipTypeDates['end_date'],
$membershipTypeDates['join_date']
$membershipTypeDates['join_date'],
$totalAmount
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ protected function assignInstalmentDetails() {
$this->instalmentsFrequencyUnit = $instalmentDetails['instalments_frequency_unit'];
}

protected function getInstalmentAmountCalculator(array $membershipTypes, $periodType = 'rolling') {
protected function getInstalmentAmountCalculator(array $membershipTypes, $periodType = 'rolling', $totalAmount = NULL, $proRated = true) {
if ($periodType == 'fixed') {
$calculator = new FixedPeriodTypeCalculator($membershipTypes);
$calculator = new FixedPeriodTypeCalculator($membershipTypes, $totalAmount, $proRated);
$calculator->setStartDate(new DateTime($this->getMembership()['start_date']));
$calculator->setEndDate(new DateTime($this->getMembership()['end_date']));
$calculator->setJoinDate(new DateTime($this->getMembership()['join_date']));
}
else {
$calculator = new RollingPeriodTypeCalculator($membershipTypes);
$calculator = new RollingPeriodTypeCalculator($membershipTypes, $totalAmount, $proRated);
}

$instalmentAmountCalculator = new InstalmentAmountCalculator($calculator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public function __construct(&$params) {
$this->setMembershipId();
$this->assignInstalmentDetails();
$this->handleContributionLineItems();
$this->instalmentAmountCalculator = $this->getInstalmentAmountCalculator($this->membershipTypeLineItems, $this->periodType);

$this->instalmentAmountCalculator = $this->getInstalmentAmountCalculator($this->membershipTypeLineItems, $this->periodType, $this->params['total_amount'], true);
}

/**
Expand Down Expand Up @@ -290,7 +291,6 @@ private function adjustMembershipFee(CRM_Member_DAO_MembershipType $membershipTy
if (!$this->isUsingPriceSet()) {
return;
}

$membershipType->minimum_fee = $lineTotal;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ public function alterLineItemParameters() {
*/
private function handleMembershipTypeLineItem() {
$lineItemMembershipType = CRM_Member_BAO_MembershipType::findById($this->params['membership_type_id']);
$totalAmount = $this->params['line_total'] + $this->params['tax_amount'];
if ($this->isUsingPriceSet()) {
//Since line item amount can be different from membership type amount
//Make sure we are using line item total amount when using PriceSet
$lineItemMembershipType->minimum_fee = $this->params['line_total'];
$totalAmount = NULL;
}
$instalmentAmountCalculator = $this->getInstalmentAmountCalculator([$lineItemMembershipType], $lineItemMembershipType->period_type);
$instalmentAmountCalculator = $this->getInstalmentAmountCalculator([$lineItemMembershipType], $lineItemMembershipType->period_type, $totalAmount, true);
$instalmentAmount = $instalmentAmountCalculator->calculateInstalmentAmount($this->getLineItemInstalmentCount($lineItemMembershipType));
$this->params['line_total'] = $instalmentAmount->getAmount();
$this->params['unit_price'] = $instalmentAmount->getAmount();
Expand Down
1 change: 1 addition & 0 deletions CRM/MembershipExtras/Page/InstalmentSchedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ private function assignInstalments() {
$params['payment_method'] = CRM_Utils_Request::retrieve('payment_method', 'Int');
$params['start_date'] = CRM_Utils_Request::retrieve('start_date', 'String');
$params['join_date'] = CRM_Utils_Request::retrieve('join_date', 'String');
$params['total_amount'] = CRM_Utils_Request::retrieve('total_amount', 'Float');

try {
$result = civicrm_api3('PaymentSchedule', $action, $params);
Expand Down
11 changes: 8 additions & 3 deletions CRM/MembershipExtras/Service/MembershipInstalmentsSchedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ class CRM_MembershipExtras_Service_MembershipInstalmentsSchedule {
* @var DateTime|null
*/
private $joinDate;
/**
* @var float
*/
private $totalAmount;
/**
* @var \CRM_MembershipExtras_Service_MembershipInstalmentAmountCalculator
*/
Expand Down Expand Up @@ -98,13 +102,14 @@ public function __construct(array $membershipTypes, string $schedule) {
* @return mixed
* @throws Exception
*/
public function generate($paymentMethod, DateTime $startDate = NULL, DateTime $endDate = NULL, DateTime $joinDate = NULL) {
public function generate($paymentMethod, DateTime $startDate = NULL, DateTime $endDate = NULL, DateTime $joinDate = NULL, $totalAmount = NULL) {
if (empty($startDate)) {
$startDate = new DateTime($this->getMembershipStartDate($this->membershipTypes[0]->id, $startDate, $endDate, $joinDate));
}
$this->startDate = $startDate;
$this->endDate = $endDate;
$this->joinDate = $joinDate;
$this->totalAmount = $totalAmount;
$this->instalmentCount = $this->getInstalmentsNumber(
$this->membershipTypes[0], $this->schedule, $this->startDate, $this->endDate, $this->joinDate
);
Expand Down Expand Up @@ -209,14 +214,14 @@ private function calculateInstalmentAmount() {
*/
private function getInstalmentAmountCalculator() {
if ($this->membershipTypes[0]->period_type == 'fixed') {
$fixedPeriodTypCalculator = new FixedPeriodTypeCalculator($this->membershipTypes);
$fixedPeriodTypCalculator = new FixedPeriodTypeCalculator($this->membershipTypes, $this->totalAmount);
$fixedPeriodTypCalculator->setStartDate($this->startDate);
$fixedPeriodTypCalculator->setEndDate($this->endDate);
$fixedPeriodTypCalculator->setJoinDate($this->joinDate);
$this->instalmentCalculator = new InstalmentAmountCalculator($fixedPeriodTypCalculator);
}
else {
$this->instalmentCalculator = new InstalmentAmountCalculator(new RollingPeriodCalculator($this->membershipTypes));
$this->instalmentCalculator = new InstalmentAmountCalculator(new RollingPeriodCalculator($this->membershipTypes, $this->totalAmount));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,15 @@ class CRM_MembershipExtras_Service_MembershipPeriodType_FixedPeriodTypeCalculato
*/
private $membershipTypes;

public function __construct(array $membershipTypes) {
private $totalAmountAfterDiscount;

private $calculateAfterProRated;

public function __construct(array $membershipTypes, $totalAmountAfterDiscount = NULL, $calculateAfterProRated = false) {
$this->instalmentTaxAmountCalculator = new MembershipInstalmentTaxAmountCalculator();
$this->membershipTypes = $membershipTypes;
$this->totalAmountAfterDiscount = $totalAmountAfterDiscount;
$this->calculateAfterProRated = $calculateAfterProRated;
}

/**
Expand All @@ -68,11 +74,13 @@ private function calculateProRatedAmount($amount, $duration, $diff) {
*/
public function calculate() {
foreach ($this->membershipTypes as $membershipType) {
$discount = 1;
$membershipTypeDurationCalculator = new MembershipTypeDurationCalculator($membershipType, new MembershipTypeDatesCalculator());
$settings = CRM_MembershipExtras_SettingsManager::getMembershipTypeSettings($membershipType->id);
$annualProRataCalculation = $settings[SettingField::ANNUAL_PRORATA_CALCULATION_ELEMENT];
$membershipAmount = $membershipType->minimum_fee;
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $membershipAmount);
$def = $taxAmount;
if ($annualProRataCalculation == self::BY_MONTHS) {
$this->proRatedUnit = self::BY_MONTHS;
$duration = self::TWELVE_MONTHS;
Expand All @@ -91,8 +99,25 @@ public function calculate() {
$this->proRatedNumber = $membershipTypeDurationCalculator->calculateDaysBasedOnDates($this->startDate, $this->endDate, $this->joinDate);
}
}

if (!empty($this->totalAmountAfterDiscount)) {
if (!$this->calculateAfterProRated) {
$discount = ($this->totalAmountAfterDiscount) / ($membershipAmount + $taxAmount);
}
}

$amount = $this->calculateProRatedAmount($membershipAmount, $duration, $this->proRatedNumber);
$taxAmount = $this->calculateProRatedAmount($taxAmount, $duration, $this->proRatedNumber);

if (!empty($this->totalAmountAfterDiscount)) {
if ($this->calculateAfterProRated) {
$discount = ($this->totalAmountAfterDiscount) / ($amount + $taxAmount);
}
}

$amount = $amount * $discount;
$taxAmount = $taxAmount * $discount;


$this->amount += $amount;
$this->taxAmount += $taxAmount;
Expand Down Expand Up @@ -187,4 +212,15 @@ private function reCalculateEndDate() {
$this->endDate->sub(new DateInterval('P1Y'));
}

private function calculateDiscount() {
$totalAmount = 0;
$discount = 1;

foreach ($this->membershipTypes as $membershipType) {
$totalAmount += $membershipType->minimum_fee;
}
$discount = $totalAmount / $this->totalAmountAfterDiscount;

return $discount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ class CRM_MembershipExtras_Service_MembershipPeriodType_RollingPeriodTypeCalcula
*/
private $membershipTypes;

public function __construct(array $membershipTypes) {
private $totalAmountAfterDiscount;

public function __construct(array $membershipTypes, $totalAmountAfterDiscount = NULL) {
$this->instalmentTaxAmountCalculator = new MembershipInstalmentTaxAmountCalculator();
$this->membershipTypes = $membershipTypes;
$this->totalAmountAfterDiscount = $totalAmountAfterDiscount;
}

/**
Expand All @@ -22,15 +25,40 @@ public function __construct(array $membershipTypes) {
* @throws Exception
*/
public function calculate() {
$discount = $this->calculateDiscount();

foreach ($this->membershipTypes as $membershipType) {
$amount = $membershipType->minimum_fee;
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $membershipType->minimum_fee);
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $amount);

$amount = $amount * $discount;
$taxAmount = $taxAmount * $discount;

$this->amount += $amount;
$this->taxAmount += $taxAmount;

$this->generateLineItem($membershipType->financial_type_id, $amount, $taxAmount);
}
}

private function calculateDiscount() {
$totalAmount = 0;
$discount = 1;

if (empty($this->totalAmountAfterDiscount)) {
return $discount;
}

foreach ($this->membershipTypes as $membershipType) {
$amount = $membershipType->minimum_fee;
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $amount);

$totalAmount += ($amount + $taxAmount);
}
if ($totalAmount != $this->totalAmountAfterDiscount) {
$discount = $this->totalAmountAfterDiscount / $totalAmount;
}

return $discount;
}
}
7 changes: 7 additions & 0 deletions api/v3/PaymentSchedule/Getbymembershiptype.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ function _civicrm_api3_payment_schedule_getbymembershiptype_spec(&$spec) {
'type' => CRM_Utils_Type::T_DATE,
'api.required' => 0,
];

$spec['total_amount'] = [
'name' => 'total_amount',
'title' => 'Total Amount',
'type' => CRM_Utils_Type::T_FLOAT,
'api.required' => 0,
];
}

/**
Expand Down
43 changes: 26 additions & 17 deletions js/paymentPlanToggler.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
* Price set, or Payment Plan Schedule
*/
function setScheduleEvents() {
let totalAmount;
$('#total_amount, #membership_type_id_1, #record_contribution').change(() => {
if (!isPaymentPlanTabActive()) {
return;
}

totalAmount = parseFloat($('#total_amount').val().replace(",", ""));
let isPriceSet = isPriceSetSelected();
if (isPriceSet) {
let selectedPriceFieldValues = getSelectedPriceFieldValues();
Expand All @@ -86,7 +87,13 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
CRM.api3('PaymentSchedule', 'getscheduleoptionsbypricefieldvalues', params).then(function (result) {
if (result.is_error === 0) {
setPaymentPlanScheduleOption(result.values);
generateInstalmentSchedule(isPriceSet);
CRM.api3('MembershipType', 'get', {
"sequential": 1,
"return": ["minimum_fee"],
"id": parseInt($('#membership_type_id_1').val()),
}).then(function() {
generateInstalmentSchedule(isPriceSet);
});
} else {
CRM.alert(result.error_message, 'Error', 'error');
}
Expand All @@ -97,7 +104,13 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
}).then(function (result) {
if (result.is_error === 0) {
setPaymentPlanScheduleOption(result.values);
generateInstalmentSchedule(isPriceSet);
CRM.api3('MembershipType', 'get', {
"sequential": 1,
"return": ["minimum_fee"],
"id": parseInt($('#membership_type_id_1').val()),
}).then(function(anotherRes) {
generateInstalmentSchedule(isPriceSet, null, totalAmount);
});
} else {
CRM.alert(result.error_message, 'Error', 'error');
}
Expand All @@ -110,15 +123,15 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
if (!isPaymentPlanTabActive()) {
return;
}
generateInstalmentSchedule(isPriceSetSelected(), $('#start_date').val());
generateInstalmentSchedule(isPriceSetSelected(), $('#start_date').val(), totalAmount);
assignFirstContributionReceiveDate();
});

$('#renewal_date').change(() => {
if (!isPaymentPlanTabActive()) {
return;
}
generateInstalmentSchedule(isPriceSetSelected(), $('#renewal_date').val());
generateInstalmentSchedule(isPriceSetSelected(), $('#renewal_date').val(), totalAmount);
assignFirstContributionReceiveDate();
});
}
Expand Down Expand Up @@ -168,7 +181,7 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
* @param {boolean} isPriceSet
* @param startDate
*/
function generateInstalmentSchedule(isPriceSet, startDate) {
function generateInstalmentSchedule(isPriceSet, startDate, totalAmount) {
let schedule = $('#payment_plan_schedule').val();
let params = {
schedule: schedule,
Expand All @@ -185,17 +198,13 @@ function paymentPlanToggler(togglerValue, currencySymbol) {
} else {
params.membership_type_id = parseInt($('#membership_type_id_1').val());
}
let url = CRM.url('civicrm/member/instalment-schedule', params, 'back');
CRM.loadPage(url, {
target: '#instalment_schedule_table',
dialog: false,
}).on('crmLoad', function (event, data) {
if (data.hasOwnProperty('is_error') && data.is_error == true) {
CRM.alert(data.error_message, 'Error', 'error');
} else {
updateTotalAmount($('#instalment-total-amount').html(), isPriceSet);
setMembershipDates($('#instalment-membership-start-date').html(), $('#instalment-membership-end-date').html());
}
params.snippet = "json";

$.post(CRM.url('civicrm/member/instalment-schedule', params, 'back'), {total_amount: totalAmount}, function(result) {
let instalmentScheduleTableContent = result['content'];
$("#instalment_schedule_table").html(instalmentScheduleTableContent);
updateTotalAmount($('#instalment-total-amount').html(), isPriceSet);
setMembershipDates($('#instalment-membership-start-date').html(), $('#instalment-membership-end-date').html());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function testInvalidScheduleWillThrowAnException() {
$params['schedule'] = 'xyz';
$params['membership_type_id'] = $membershipType['id'];
$params['payment_method'] = $this->getPaymentMethodValue();
$params['total_amount'] = $membershipType['minimum_fee'];
$schedule = new CRM_MembershipExtras_API_PaymentSchedule_MembershipType($params);
$schedule->getPaymentSchedule();
}
Expand Down

0 comments on commit 3b44811

Please sign in to comment.