Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAE-928: Fix discount when the payment plan tab is selected #458

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 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 @@ -63,7 +64,8 @@ protected function getInstalments(array $membershipTypes, array $nonMembershipPr
$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, $proRatedCalculated = TRUE) {
if ($periodType == 'fixed') {
$calculator = new FixedPeriodTypeCalculator($membershipTypes);
$calculator = new FixedPeriodTypeCalculator($membershipTypes, $totalAmount, $proRatedCalculated);
$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, $proRatedCalculated);
}

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

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

/**
Expand Down Expand Up @@ -290,7 +292,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
12 changes: 9 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 @@ -94,17 +98,19 @@ public function __construct(array $membershipTypes, string $schedule) {
* @param DateTime|null $startDate
* @param DateTime|null $endDate
* @param DateTime|null $joinDate
* @param float|null $totalAmount
*
* @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 +215,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 @@ -44,10 +44,20 @@ class CRM_MembershipExtras_Service_MembershipPeriodType_FixedPeriodTypeCalculato
* @var array
*/
private $membershipTypes;
/**
* @var float|null
*/
private $totalAmount;
/**
* @var bool
*/
private $proRatedCalculated;

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

/**
Expand All @@ -68,6 +78,7 @@ 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];
Expand All @@ -91,9 +102,21 @@ public function calculate() {
$this->proRatedNumber = $membershipTypeDurationCalculator->calculateDaysBasedOnDates($this->startDate, $this->endDate, $this->joinDate);
}
}

if (!empty($this->totalAmount) && !$this->proRatedCalculated) {
$discount = $this->totalAmount / ($membershipAmount + $taxAmount);
}

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

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ class CRM_MembershipExtras_Service_MembershipPeriodType_RollingPeriodTypeCalcula
* @var array
*/
private $membershipTypes;
/**
* @var float|null
*/
private $totalAmountAfterDiscount;

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

/**
Expand All @@ -23,8 +28,17 @@ public function __construct(array $membershipTypes) {
*/
public function calculate() {
foreach ($this->membershipTypes as $membershipType) {
$discount = 1;
$amount = $membershipType->minimum_fee;
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $membershipType->minimum_fee);
$taxAmount = $this->instalmentTaxAmountCalculator->calculateByMembershipType($membershipType, $amount);

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

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

$this->amount += $amount;
$this->taxAmount += $taxAmount;
Expand Down
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
45 changes: 28 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,15 @@ 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());
}).fail(function(response) {
CRM.alert(response.responseText, 'Error', 'error');
});
}

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