Skip to content

Commit

Permalink
Merge branch 'bexley-ww-garden-direct-debit-confirm-reports' into com…
Browse files Browse the repository at this point in the history
…mercial-staging
  • Loading branch information
davea committed Feb 20, 2025
2 parents 9db9855 + 8d2cd90 commit 08205ca
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 14 deletions.
8 changes: 6 additions & 2 deletions perllib/FixMyStreet/App/Controller/Waste.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1614,9 +1614,13 @@ sub process_garden_data : Private {
sub garden_calculate_subscription_payment : Private {
my ($self, $c, $type, $data) = @_;

# Sack form handling
my $container = $data->{container_choice} || '';
my $costs = WasteWorks::Costs->new({ cobrand => $c->cobrand, discount => $data->{apply_discount} });
my $costs = WasteWorks::Costs->new({
cobrand => $c->cobrand,
discount => $data->{apply_discount},
first_bin_discount => $c->cobrand->call_hook('garden_waste_first_bin_discount_applies' => $data)
});
# Sack form handling
if ($container eq 'sack') {
if ($c->cobrand->moniker eq 'merton') {
# If renewing from bin to sacks, need to know bins to remove - better place for this?
Expand Down
12 changes: 10 additions & 2 deletions perllib/FixMyStreet/App/Form/Waste/Garden.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ sub details_update_fields {
my $bin_count = $c->get_param('bins_wanted') || $form->saved_data->{bins_wanted} || $existing;
my $new_bins = $bin_count - $current_bins;

my $costs = WasteWorks::Costs->new({ cobrand => $c->cobrand, discount => $data->{apply_discount} });
my $costs = WasteWorks::Costs->new({
cobrand => $c->cobrand,
discount => $data->{apply_discount},
first_bin_discount => $c->cobrand->call_hook('garden_waste_first_bin_discount_applies' => $data)
});
my $cost_pa = $bin_count == 0 ? 0 : $costs->bins($bin_count);
my $cost_now_admin = $costs->new_bin_admin_fee($new_bins);
$c->stash->{cost_pa} = $cost_pa / 100;
Expand Down Expand Up @@ -104,7 +108,11 @@ has_page summary => (
my $bin_count = $data->{bins_wanted} || 1;
my $new_bins = $bin_count - $current_bins;
my $cost_pa;
my $costs = WasteWorks::Costs->new({ cobrand => $c->cobrand, discount => $data->{apply_discount} });
my $costs = WasteWorks::Costs->new({
cobrand => $c->cobrand,
discount => $data->{apply_discount},
first_bin_discount => $c->cobrand->call_hook('garden_waste_first_bin_discount_applies' => $data)
});
if (($data->{container_choice}||'') eq 'sack') {
$cost_pa = $costs->sacks($bin_count);
} else {
Expand Down
13 changes: 13 additions & 0 deletions perllib/FixMyStreet/Cobrand/Bexley/Garden.pm
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ sub waste_setup_direct_debit {
$report->set_extra_metadata('direct_debit_customer_id', $customer->{Id});
$report->set_extra_metadata('direct_debit_contract_id', $contract->{Id});
$report->set_extra_metadata('direct_debit_reference', $contract->{DirectDebitRef});
$report->confirm;
$report->update;

return 1;
Expand All @@ -280,4 +281,16 @@ sub waste_garden_subscribe_form_setup {
$self->{c}->stash->{form_class} = 'FixMyStreet::App::Form::Waste::Garden::Bexley';
}

=head2 * garden_waste_first_bin_discount_applies
The cost of the first garden waste bin is discounted if the payment method
is direct debit.
=cut

sub garden_waste_first_bin_discount_applies {
my ($self, $data) = @_;
return $data->{payment_method} && $data->{payment_method} eq 'direct_debit';
}

1;
13 changes: 13 additions & 0 deletions perllib/WasteWorks/Costs.pm
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ use Types::Standard qw(Bool Enum);

has cobrand => ( is => 'ro' ); # Cobrand we're working with, to get actual data
has discount => ( is => 'rw', isa => Bool ); # If a discount is applied (Brent only)
has first_bin_discount => ( is => 'rw', isa => Bool ); # If a discount should be applied to the first bin

has service => ( is => 'lazy' ); # Existing garden service (for the end date)
has payments => ( is => 'lazy' );
has discount_amount => ( is => 'lazy' );
has first_bin_discount_absolute_amount => ( is => 'lazy' );
has renewal_type => ( is => 'lazy', isa => Enum['current', 'subscription_end'] );
has has_pro_rata_modify => ( is => 'lazy', isa => Bool );

Expand All @@ -24,6 +26,11 @@ sub _build_discount_amount {
return $features->{ggw_discount_as_percent};
}

sub _build_first_bin_discount_absolute_amount {
my $features = $_[0]->cobrand->feature('payment_gateway') || {};
return $features->{ggw_first_bin_discount} // 0;
}

sub _build_renewal_type {
return 'subscription_end' if $_[0]->cobrand->moniker eq 'kingston' || $_[0]->cobrand->moniker eq 'bromley';
return 'current';
Expand All @@ -38,6 +45,9 @@ sub bins {
$count ||= 1;
my $per_bin = $self->get_cost('ggw_cost') ;
my $first_cost = $self->get_cost('ggw_cost_first') || $per_bin;
if ($self->first_bin_discount) {
$first_cost -= $self->first_bin_discount_absolute_amount;
}
my $cost = $self->_first_diff_calc($first_cost, $per_bin, $count);
return $cost;
}
Expand All @@ -60,6 +70,9 @@ sub _renewal {
my $first_cost = $self->get_cost($prefix . '_renewal_first', $end_date)
|| $self->get_cost($prefix . '_first', $end_date)
|| $cost;
if ($self->first_bin_discount) {
$first_cost -= $self->first_bin_discount_absolute_amount;
}
$cost = $self->_first_diff_calc($first_cost, $cost, $count);
return $cost;
} elsif ($type eq 'sacks') {
Expand Down
80 changes: 76 additions & 4 deletions t/app/controller/waste_bexley_garden.t
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ FixMyStreet::override_config {
} },
agile => { bexley => { url => 'test' } },
payment_gateway => { bexley => {
ggw_first_bin_discount => 500,
ggw_cost_first => 7500,
ggw_cost => 5500,
cc_url => 'http://example.org/cc_submit',
Expand Down Expand Up @@ -269,6 +270,46 @@ FixMyStreet::override_config {
$mech->clear_emails_ok;
};

subtest 'check new sub direct debit applies first bin discount payment' => sub {
my $test = {
month => '01',
pounds_cost => '125.00',
pence_cost => '12500'
};
set_fixed_time("2021-$test->{month}-09T17:00:00Z");
$mech->get_ok('/waste/10001/garden');
$mech->submit_form_ok({ form_number => 1 });
$mech->submit_form_ok({ with_fields => { existing => 'no' } });
$mech->content_like(qr#Total to pay now: £<span[^>]*>0.00#, "initial cost set to zero");
$mech->submit_form_ok({ with_fields => {
current_bins => 0,
bins_wanted => 2,
payment_method => 'direct_debit',
name => 'Test McTest',
email => '[email protected]'
} });
$mech->text_contains(
'Please provide your bank account information so we can set up your Direct Debit mandate',
'On DD details form',
);

my %dd_fields = (
name_title => 'Mr',
first_name => 'Test',
surname => 'McTest',
address1 => '1 Test Street',
address2 => 'Test Area',
post_code => 'DA1 1AA',
account_holder => 'Test McTest',
account_number => '12345678',
sort_code => '12-34-56'
);
$mech->submit_form_ok( { with_fields => \%dd_fields } );

$mech->content_contains('Test McTest');
$mech->content_contains('£' . $test->{pounds_cost});
};

set_fixed_time('2023-01-09T17:00:00Z'); # Set a date when garden service full price for most tests

subtest 'check new sub credit card payment with no bins required' => sub {
Expand Down Expand Up @@ -430,6 +471,9 @@ FixMyStreet::override_config {
};

subtest 'Test direct debit submission flow new customer' => sub {
$mech->clear_emails_ok;
FixMyStreet::DB->resultset("Problem")->delete_all;

my $access_mock = Test::MockModule->new('Integrations::AccessPaySuite');
my ($customer_params, $contract_params);
$access_mock->mock('create_customer', sub {
Expand Down Expand Up @@ -473,7 +517,7 @@ FixMyStreet::override_config {
$mech->content_contains('Please review the information you’ve provided before you submit your garden subscription');

$mech->content_contains('Test McTest');
$mech->content_contains('£75.00');
$mech->content_contains('£70.00');
$mech->submit_form_ok({ with_fields => { tandc => 1 } });

my $report = FixMyStreet::DB->resultset("Problem")->order_by('-id')->first;
Expand Down Expand Up @@ -505,7 +549,7 @@ FixMyStreet::override_config {
atTheEnd => 'Switch to further notice',
paymentDayInMonth => 28,
paymentMonthInYear => 1,
amount => '75.00',
amount => '70.00',
start => '2023-01-23T17:00:00.000',
additionalReference => "BEX-$id-10001",
}, 'Contract parameters are correct';
Expand All @@ -516,9 +560,25 @@ FixMyStreet::override_config {
is $report->get_extra_metadata('direct_debit_customer_id'), 'CUSTOMER123', 'Correct customer ID';
is $report->get_extra_metadata('direct_debit_contract_id'), 'CONTRACT123', 'Correct contract ID';
is $report->get_extra_metadata('direct_debit_reference'), 'APIRTM-DEFGHIJ1KL', 'Correct payer reference';
is $report->state, 'confirmed', 'Report is confirmed';

FixMyStreet::Script::Reports::send();
my @emails = $mech->get_email;
my $body = $mech->get_text_body_from_email($emails[1]);
TODO: {
local $TODO = 'Quantity not yet read in _garden_data.html';
like $body, qr/Number of bin subscriptions: 2/;
}
like $body, qr/Bins to be delivered: 1/;
like $body, qr/Total:.*?70/;
$mech->clear_emails_ok;

};

subtest 'Test direct debit submission flow existing customer' => sub {
$mech->clear_emails_ok;
FixMyStreet::DB->resultset("Problem")->delete_all;

my $access_mock = Test::MockModule->new('Integrations::AccessPaySuite');
my ($customer_params, $contract_params);
$access_mock->mock('create_customer', sub {
Expand Down Expand Up @@ -563,7 +623,7 @@ FixMyStreet::override_config {
$mech->content_contains('Please review the information you’ve provided before you submit your garden subscription');

$mech->content_contains('Test McTest');
$mech->content_contains('£75.00');
$mech->content_contains('£70.00');
$mech->submit_form_ok({ with_fields => { tandc => 1 } });

my $report = FixMyStreet::DB->resultset("Problem")->order_by('-id')->first;
Expand All @@ -581,7 +641,7 @@ FixMyStreet::override_config {
atTheEnd => 'Switch to further notice',
paymentDayInMonth => 28,
paymentMonthInYear => 1,
amount => '75.00',
amount => '70.00',
start => '2023-01-23T17:00:00.000',
additionalReference => "BEX-$id-10001"
}, 'Contract parameters are correct';
Expand All @@ -592,6 +652,18 @@ FixMyStreet::override_config {
is $report->get_extra_metadata('direct_debit_customer_id'), 'CUSTOMER456', 'Correct customer ID';
is $report->get_extra_metadata('direct_debit_contract_id'), 'CONTRACT123', 'Correct contract ID';
is $report->get_extra_metadata('direct_debit_reference'), 'APIRTM-DEFGHIJ1KL', 'Correct payer reference';
is $report->state, 'confirmed', 'Report is confirmed';

FixMyStreet::Script::Reports::send();
my @emails = $mech->get_email;
my $body = $mech->get_text_body_from_email($emails[1]);
TODO: {
local $TODO = 'Quantity not yet read in _garden_data.html';
like $body, qr/Number of bin subscriptions: 2/;
}
like $body, qr/Bins to be delivered: 1/;
like $body, qr/Total:.*?70/;
$mech->clear_emails_ok;
};

subtest 'cancel garden subscription' => sub {
Expand Down
10 changes: 8 additions & 2 deletions t/wasteworks/costs.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ my $brent = FixMyStreet::Cobrand::Brent->new; # Discount
my $kingston = FixMyStreet::Cobrand::Kingston->new; # Renews with end date, admin fee
my $sutton = FixMyStreet::Cobrand::Sutton->new; # Next month
my $merton = FixMyStreet::Cobrand::Merton->new;
my $bexley = FixMyStreet::Cobrand::Bexley->new;
my $bexley = FixMyStreet::Cobrand::Bexley->new; # First bin discount

set_fixed_time("2025-01-14T12:00:00Z");

Expand All @@ -30,7 +30,7 @@ FixMyStreet::override_config {
{ start_date => '2025-01-01 00:00', cost => 1500 },
{ start_date => '2025-02-01 00:00', cost => 1700 },
] },
bexley => { ggw_cost_first => 7500, ggw_cost => 5500 },
bexley => { ggw_first_bin_discount => 500, ggw_cost_first => 7500, ggw_cost => 5500 },
},
waste_features => {
brent => { ggw_discount_as_percent => 20 },
Expand Down Expand Up @@ -59,6 +59,12 @@ FixMyStreet::override_config {
is $costs->bins(2), 7500+5500;
};

subtest 'first bin discounted' => sub {
my $costs = WasteWorks::Costs->new({ cobrand => $bexley, discount => 0, first_bin_discount => 1, service => $mocked_service });
is $costs->bins, 7000;
is $costs->bins(2), 7000+5500;
};

subtest 'sacks' => sub {
my $costs = WasteWorks::Costs->new({ cobrand => $merton });
is $costs->sacks(1), 750;
Expand Down
11 changes: 10 additions & 1 deletion templates/web/base/waste/garden/_bin_quantities.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,18 @@ <h2 class="govuk-fieldset__heading">How many bins do you need us to empty each t
<div class="fieldset-item">
[% IF form_page == 'renew';
SET cost = garden_costs.per_bin_renewal;
SET first_cost = garden_costs.per_bin_renewal_first;
ELSE;
SET cost = garden_costs.per_bin;
SET first_cost = garden_costs.per_bin_first;
END %]
<span class="cost-pa" id="total_per_year">£[% tprintf('%.2f', cost / 100 ) %] per bin per year</span>

[% IF cost != first_cost %]
<span "cost-pa">£<span id="first-bin-cost-pa">[% tprintf('%.2f', first_cost / 100 ) %]</span> per year for the first bin.</span>
<br>
<span "cost-pa">£<span id="general-bin-cost-pa">[% tprintf('%.2f', cost / 100 ) %]</span> per bin per year for the rest.</span>
[% ELSE %]
<span class="cost-pa" id="total_per_year">£[% tprintf('%.2f', cost / 100 ) %] per bin per year</span>
[% END %]
</div>
</div>
1 change: 1 addition & 0 deletions templates/web/base/waste/garden/subscribe_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<hr class="fieldset-hr">

<div class="cost-pa__total js-bin-costs"
data-first_bin_discount="[% garden_costs.first_bin_discount_absolute_amount %]"
data-per_bin_cost="[% garden_costs.per_bin %]"
data-per_bin_first_cost="[% garden_costs.per_bin_first %]"
data-per_new_bin_first_cost="[% garden_costs.per_new_bin_first %]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@
</div>
<div class="waste-service-hint__content">
<p>
[% IF cobrand.moniker == 'brent' %]
[% IF cobrand.moniker == 'bexley' %]
[%
SET first_bin_discount = garden_costs.first_bin_discount_absolute_amount / 100;
-%]
Each garden waste bin holds 240 litres of waste. We collect them every 2 weeks.<br>
Note the first bin costs £[% tprintf('%.2f', first_bin_discount) %] less if you choose to pay by Direct Debit.
[% ELSIF cobrand.moniker == 'brent' %]
Our 240 litre wheelie bins are green, and hold the equivalent of 5 or 6 bags of green garden waste.
[% ELSIF cobrand.moniker == 'bromley' %]
Each wheelie bin holds the equivalent of 5 or 6 bags of green garden waste,
Expand Down
3 changes: 2 additions & 1 deletion templates/web/base/waste/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
version('/vendor/accessible-autocomplete.min.js'),
version('/js/waste.js')
];
# Bexley want external links to open in new tab
SET external_new_tab = '';
IF c.cobrand.moniker == 'bexley';
# Bexley want external links to open in new tab
SET external_new_tab = 'target="_blank"';
extra_js.push(version('/cobrands/bexley/waste.js'));
END;
INCLUDE header.html;
END;
Expand Down
17 changes: 17 additions & 0 deletions web/cobrands/bexley/waste.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
window.garden_waste_first_bin_discount_applies = function() {
return $('input[name="payment_method"]:checked').val() === 'direct_debit';
};

$(function() {
// If there's an error when submitting the subscribe form,
// the first bin discount won't be displayed even when it should apply.
// This is due to how the form is set-up on the server.
// We work around this by just checking if the discount should apply
// when the page loads and running the cost calculation function if so.
window.onload = function() {
if (window.garden_waste_first_bin_discount_applies()) {
window.garden_waste_bin_cost_new();
}
};
$('#subscribe_details input[name="payment_method"]').on('change', window.garden_waste_bin_cost_new);
});
Loading

0 comments on commit 08205ca

Please sign in to comment.