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

[Bexley][WW] Renew GGW subscription #5366

Open
wants to merge 11 commits into
base: bexley-ww-ggw-show-existing
Choose a base branch
from
163 changes: 136 additions & 27 deletions perllib/FixMyStreet/Cobrand/Bexley/Garden.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use DateTime::Format::Strptime;
use Integrations::Agile;
use FixMyStreet::App::Form::Waste::Garden::Cancel::Bexley;
use Try::Tiny;
use JSON::MaybeXS;

use Moo::Role;
with 'FixMyStreet::Roles::Cobrand::SCP',
Expand All @@ -29,55 +31,119 @@
return [ 'GA-140', 'GA-240' ];
}

sub garden_current_subscription {
my $self = shift;
sub lookup_subscription_for_uprn {
my ($self, $uprn) = @_;

Check warning on line 35 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L35

Added line #L35 was not covered by tests

my $current = $self->{c}->stash->{property}{garden_current_subscription};
return $current if $current;
my $sub = {

Check warning on line 37 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L37

Added line #L37 was not covered by tests
row => undef,

my $uprn = $self->{c}->stash->{property}{uprn};
return undef unless $uprn;

# TODO Fetch active subscription from DB for UPRN
# (get_original_sub() in Controller/Waste.pm needs to handle Bexley UPRN).
# Could be more than one customer, so match against email.
# Could be more than one contract, so match against reference.
email => undef,
cost => undef,
end_date => undef,
customer_external_ref => undef,
bins_count => undef,
};

my $results = $self->agile->CustomerSearch($uprn);
return undef unless $results && $results->{Customers};
my $customer = $results->{Customers}[0];
return undef unless $customer && $customer->{ServiceContracts};
my $contract = $customer->{ServiceContracts}[0];
# Assume there is only one active subscription
my ($contract) = grep {
$_->{ServiceContractStatus} eq 'ACTIVE'
|| $_->{ServiceContractStatus} eq 'PRECONTRACT'
} @{ $customer->{ServiceContracts} // [] };

Check warning on line 55 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L55

Added line #L55 was not covered by tests
return unless $contract;

my $parser
= DateTime::Format::Strptime->new( pattern => '%d/%m/%Y %H:%M' );
my $end_date = $parser->parse_datetime( $contract->{EndDate} );
# XXX should maybe sort by CreatedDate rather than assuming first is OK
$sub->{cost} = try {
my ($payment) = grep { $_->{PaymentStatus} eq 'Paid' } @{ $contract->{Payments} };
return $payment->{Amount};
};

Check warning on line 62 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L60-L62

Added lines #L60 - L62 were not covered by tests

my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y %H:%M' );
$sub->{end_date} = $parser->parse_datetime( $contract->{EndDate} );

Check warning on line 65 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L64-L65

Added lines #L64 - L65 were not covered by tests

$sub->{customer_external_ref} = $customer->{CustomerExternalReference};

Check warning on line 67 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L67

Added line #L67 was not covered by tests

$sub->{bins_count} = $contract->{WasteContainerQuantity};

Check warning on line 69 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L69

Added line #L69 was not covered by tests

my $c = $self->{c};

Check warning on line 71 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L71

Added line #L71 was not covered by tests
my $p = $c->model('DB::Problem')->search({
category => 'Garden Subscription',
extra => { '@>' => encode_json({ "_fields" => [ { name => "uprn", value => $uprn } ] }) },
state => { '!=' => 'hidden' },
external_id => "Agile-" . $contract->{Reference},
})->order_by('-id')->to_body($c->cobrand->body)->first;

Check warning on line 77 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L77

Added line #L77 was not covered by tests

if ($p) {
$self->{c}->stash->{orig_sub} = $sub->{row} = $p;

Check warning on line 80 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L80

Added line #L80 was not covered by tests
}

return $sub;

Check warning on line 83 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L83

Added line #L83 was not covered by tests
}

sub garden_current_subscription {
my ($self, $services) = @_;

Check warning on line 87 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L87

Added line #L87 was not covered by tests

my $current = $self->{c}->stash->{property}{garden_current_subscription};

Check warning on line 89 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L89

Added line #L89 was not covered by tests
return $current if $current;

my $uprn = $self->{c}->stash->{property}{uprn};

Check warning on line 92 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L92

Added line #L92 was not covered by tests
return undef unless $uprn;

my $sub = $self->lookup_subscription_for_uprn($uprn);

Check warning on line 95 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L95

Added line #L95 was not covered by tests
return undef unless $sub;

my $garden_due = $self->waste_sub_due( $sub->{end_date} );

Check warning on line 98 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L98

Added line #L98 was not covered by tests

# Agile says there is a subscription; now get service data from
# Whitespace
my $services = $self->{c}->stash->{services};
my $service_ids = { map { $_->{service_id} => $_ } @$services };

Check warning on line 102 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L102

Added line #L102 was not covered by tests
for ( @{ $self->garden_service_ids } ) {
if ( my $srv = $services->{$_} ) {
$srv->{customer_external_ref}
= $customer->{CustomerExternalReference};
$srv->{end_date} = $end_date;
if ( my $srv = $service_ids->{$_} ) {
$srv->{customer_external_ref} = $sub->{customer_external_ref};
$srv->{end_date} = $sub->{end_date};
$srv->{garden_bins} = $sub->{bins_count};
$srv->{garden_cost} = $sub->{cost};
$srv->{garden_due} = $garden_due;

Check warning on line 109 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L105-L109

Added lines #L105 - L109 were not covered by tests

return $srv;
}
}

return {
# If we reach here then Whitespace doesn't think there's a garden service for this
# property. If Agile does have a subscription then we need to add a service
# to the list for this property so the frontend displays it.
my $service = {
agile_only => 1,
customer_external_ref => $customer->{CustomerExternalReference},
end_date => $end_date,
customer_external_ref => $sub->{customer_external_ref},
end_date => $sub->{end_date},
garden_bins => $sub->{bins_count},
garden_cost => $sub->{cost},
garden_due => $garden_due,

Check warning on line 124 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L124

Added line #L124 was not covered by tests

uprn => $uprn,
garden_waste => 1,
service_description => "Garden waste",
service_name => "Brown wheelie bin",
service_id => "GA-240",
schedule => "Pending",
next => { pending => 1 },
};
push @$services, $service;
$self->{c}->stash->{property}{garden_current_subscription} = $service;
$self->{c}->stash->{property}{has_garden_subscription} = 1;
return $service;

Check warning on line 137 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L134-L137

Added lines #L134 - L137 were not covered by tests
}

# TODO This is a placeholder
sub get_current_garden_bins { 1 }
sub get_current_garden_bins { shift->garden_current_subscription->{garden_bins} }

Check warning on line 140 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L140

Added line #L140 was not covered by tests

sub waste_cancel_asks_staff_for_user_details { 1 }

# TODO Needs to check 14-day window after subscription started
sub waste_garden_allow_cancellation { 'all' }

Check warning on line 145 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L145

Added line #L145 was not covered by tests

sub waste_cancel_form_class {
'FixMyStreet::App::Form::Waste::Garden::Cancel::Bexley';
}
Expand All @@ -86,10 +152,9 @@
my ( $self, $data, $type ) = @_;

my $c = $self->{c};
my $srv = $self->garden_current_subscription;

Check warning on line 155 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L155

Added line #L155 was not covered by tests

if ( $data->{category} eq 'Cancel Garden Subscription' ) {
my $srv = $self->garden_current_subscription;

my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' );
my $due_date_str = $parser->format_datetime( $srv->{end_date} );

Expand All @@ -100,9 +165,53 @@
$c->set_param( 'customer_external_ref', $srv->{customer_external_ref} );
$c->set_param( 'due_date', $due_date_str );
$c->set_param( 'reason', $reason );

} elsif ( $data->{title} =~ /Renew/ ) {
$c->set_param( 'type', 'renew' );
$c->set_param( 'customer_external_ref', $srv->{customer_external_ref} );
$c->set_param( 'total_containers', $data->{bins_wanted} );

Check warning on line 172 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L170-L172

Added lines #L170 - L172 were not covered by tests

} elsif ( $data->{category} eq 'Garden Subscription' ) {
$c->set_param( 'total_containers', $data->{bins_wanted} );

Check warning on line 175 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L175

Added line #L175 was not covered by tests

}
}

sub garden_due_days { 42 }

Check warning on line 180 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L180

Added line #L180 was not covered by tests

=head2 waste_sub_due

Returns true/false if now is less than garden_due_days before DATE.

=cut

sub waste_sub_due {
my ( $self, $date ) = @_;

Check warning on line 189 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L189

Added line #L189 was not covered by tests

my $now = DateTime->now->set_time_zone( FixMyStreet->local_time_zone );
my $sub_end = DateTime::Format::W3CDTF->parse_datetime($date);

Check warning on line 192 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L191-L192

Added lines #L191 - L192 were not covered by tests

my $diff = $now->delta_days($sub_end)->in_units('days');
return $diff <= $self->garden_due_days;

Check warning on line 195 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L194-L195

Added lines #L194 - L195 were not covered by tests
}

=head2 waste_sub_overdue

Returns true/false if now is past DATE.

=cut

sub waste_sub_overdue {
my ( $self, $date ) = @_;

Check warning on line 205 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L205

Added line #L205 was not covered by tests

my $now = DateTime->now->set_time_zone( FixMyStreet->local_time_zone )

Check warning on line 207 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L207

Added line #L207 was not covered by tests
->truncate( to => 'day' );
my $sub_end = DateTime::Format::W3CDTF->parse_datetime($date)

Check warning on line 209 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L209

Added line #L209 was not covered by tests
->truncate( to => 'day' );

return $now > $sub_end;

Check warning on line 212 in perllib/FixMyStreet/Cobrand/Bexley/Garden.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Garden.pm#L212

Added line #L212 was not covered by tests
}

=item * You can order a maximum of five bins

=cut
Expand Down
9 changes: 5 additions & 4 deletions perllib/FixMyStreet/Cobrand/Bexley/Waste.pm
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@
},
assisted_collection => $assisted_collection,
uprn => $uprn,
garden_waste => $container->{description} eq 'Garden waste' ? 1 : 0,
};

if ($last_dt) {
Expand All @@ -398,7 +399,7 @@
$property->{above_shop} = 1
if $filtered_service->{service_id} eq 'MDR-SACK';
$property->{has_garden_subscription} = 1
if $filtered_service->{service_description} eq 'Garden waste';
if $filtered_service->{garden_waste};

# Frequency of collection
if ( @round_schedules > 1 ) {
Expand Down Expand Up @@ -459,13 +460,13 @@
];
}

$property->{garden_current_subscription}
= $self->garden_current_subscription;

@site_services_filtered = $self->_remove_service_if_assisted_exists(@site_services_filtered);

@site_services_filtered = $self->service_sort(@site_services_filtered);

$property->{garden_current_subscription}
= $self->garden_current_subscription(\@site_services_filtered);

Check warning on line 468 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L468

Added line #L468 was not covered by tests

$self->_set_request_containers( $property, @site_services_filtered );

return \@site_services_filtered;
Expand Down
1 change: 1 addition & 0 deletions t/app/controller/waste_bexley.t
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ FixMyStreet::override_config {
date => ignore(),
},
uprn => ignore(),
garden_waste => 0,
);
cmp_deeply \@sorted, [
{ id => 8,
Expand Down
3 changes: 2 additions & 1 deletion t/app/controller/waste_bexley_garden.t
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ FixMyStreet::override_config {

subtest 'with Agile data only' => sub {
$mech->get_ok('/waste/10001');
like $mech->text, qr/Sorry, we are unable to find any rubbish and recycling collections/;
like $mech->text, qr/Brown wheelie bin/;
like $mech->text, qr/Next collectionPending/;

$mech->get_ok('/waste/10001/garden_cancel');
like $mech->text, qr/Cancel your garden waste subscription/;
Expand Down
62 changes: 62 additions & 0 deletions templates/web/base/waste/_services_garden_current.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

<dl class="govuk-summary-list">
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">Subscription</dt>
<dd class="govuk-summary-list__value">
[%~ PROCESS 'waste/_services_garden_subscription.html' ~%]
</dd>
</div>
[% IF unit.end_date %]
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">Renewal</dt>
<dd class="govuk-summary-list__value
[%~ ' renewal-status' IF unit.garden_due AND NOT waste_features.garden_renew_disabled ~%]
">[% date.format(unit.end_date _ ' 00:00:00', '%d %B %Y') %]
[%~ ' Cancellation in progress' IF pending_cancellation %]
[%~ ', soon due for renewal.' IF unit.garden_due AND NOT waste_features.garden_renew_disabled ~%]
</dd>
</div>
[% END %]
</dl>

[% IF ( unit.garden_due ) AND NOT waste_features.garden_renew_disabled %]
<form method="post" action="[% c.uri_for_action('waste/garden_renew', [ property.id ]) %]">
<input type="hidden" name="token" value="[% csrf_token %]">
<input type="submit" value="[% IF c.cobrand.moniker == 'merton' %]Renew without making changes[% ELSE %]Renew your [% unit.service_name FILTER lower %] subscription[% END %]" class="waste-service-descriptor waste-service-link">
</form>
[% IF c.cobrand.moniker == 'merton' %]
<p class="govuk-body-s govuk-!-margin-top-2">
If you do wish to make changes, please wait and reapply after
[% date.format(unit.end_date _ ' 00:00:00', '%A %-d %B') %].
</p>
[% END %]
[% END %]

[% IF NOT pending_cancellation %]
[% IF NOT unit.garden_due AND NOT waste_features.garden_modify_disabled AND c.cobrand.waste_show_garden_modify(unit) %]
<form method="post" action="[% c.uri_for_action('waste/garden_modify', [ property.id ]) %]">
<input type="hidden" name="token" value="[% csrf_token %]">
[% IF c.cobrand.moniker == 'kingston' AND (slwp_garden_sacks AND unit.garden_sacks) %]
<input type="submit" value="Order more garden sacks" class="waste-service-descriptor waste-service-link">
[% ELSE %]
<input type="submit" value="Change your [% unit.service_name FILTER lower %] subscription" class="waste-service-descriptor waste-service-link">
[% END %]
</form>
[% ELSIF c.cobrand.moniker == 'brent' AND NOT is_staff %]
<p>
If you are looking to pay for another garden waste service, please <a href="https://customerportal.brent.gov.uk/contact-centre-anonymous/cc-enquirytype-anonymous/?sid=4933b2f4-dc86-e911-a8f4-00224801ab35&sname=Waste">contact our Customer Services Team</a>.
</p>
[% END %]
[% IF ( c.cobrand.call_hook('waste_garden_allow_cancellation') == 'staff' AND is_staff ) OR c.cobrand.call_hook('waste_garden_allow_cancellation') == 'all' %]
<form method="post" action="[% c.uri_for_action('waste/garden_cancel', [ property.id ]) %]">
<input type="hidden" name="token" value="[% csrf_token %]">
<input type="submit" value="Cancel your [% unit.service_name FILTER lower %] subscription" class="waste-service-descriptor waste-service-link">
</form>
[% END %]

[% IF c.cobrand.moniker == 'merton' AND is_staff %]
<!--
<a href="[% c.uri_for_action('waste/enquiry', [ property.id ]) %]?category=Garden+Subscription+Address+Change&amp;service_id=[% unit.service_id %]" class="waste-service-link waste-service-descriptor">Report an address change</a>
-->
[% END %]
[% END %]
2 changes: 2 additions & 0 deletions templates/web/base/waste/bin_days.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ <h3 class="govuk-heading-l govuk-warning-text__heading">Your subscription is soo
[% END %]
[% ELSIF unit.next.is_today %]
<strong>Being collected today</strong>
[% ELSIF unit.next.pending %]
<strong>Pending</strong>
[% ELSE %]
[% date.format(unit.next.date) | replace('~~~', unit.next.ordinal) %]
[% END %]
Expand Down
Loading
Loading