summaryrefslogtreecommitdiff
path: root/FS/FS/part_event/Action/pkg_discount.pm
blob: d245ef40be923ca438fb0078d20dc02c3d397f09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package FS::part_event::Action::pkg_discount;

use strict;
use base qw( FS::part_event::Action );

sub description { "Discount unsuspended package(s) (monthly recurring only)"; }

sub eventtable_hashref {
  { 'cust_main' => 1,
    'cust_pkg'  => 1,
  };
}

sub event_stage { 'pre-bill'; }

sub option_fields {
  (
    'if_pkgpart'  => { 'label'    => 'Only packages',
                       'type'     => 'select-table',
                       'table'    => 'part_pkg',
                       'name_col' => 'pkg',
                       #can tweak after fixing discount bug with non-monthly recurring pkgs 
                       'extra_sql' => q(AND freq NOT LIKE '0%' AND freq NOT LIKE '%d' AND freq NOT LIKE '%h' AND freq NOT LIKE '%w'), 
                       'multiple' => 1,
                     },
    'if_pkg_class' => { 'label'    => 'Only package class',
                        'type'     => 'select-pkg_class',
                        'multiple' => 1,
                      },
    'discountnum' => { 'label'    => 'Discount',
                       'type'     => 'select-table', #we don't handle the select-discount create a discount case
                       'table'    => 'discount',
                       #(well, since 2013 it winds up calling select-discount
                       # anyway (but not tr-select-discount)
                       #'name_col' => 'description', #well, method
                       #'order_by' => 'ORDER BY discountnum', #requied because name_col is a method
                       'disable_empty' => 1,
                       'hashref'  => { 'disabled' => '',
                                       'months'   => { op=>'!=', value=>'0' },
                                     },
                       'disable_custom_discount' => 1,
                     },
    'once_percust' => { 'label' => 'Only discount one package per customer',
                        'type'  => 'checkbox',
                        'value' => 'Y',
                      },
  );
}

#lots of false laziness with referral_pkg_discount
#but also lots of doing it differently...and better???
sub do_action {
  my( $self, $object, $cust_event ) = @_;

  my $cust_main = $self->cust_main($object);
  my %if_pkgpart = map { $_=>1 } split(/\s*,\s*/, $self->option('if_pkgpart') );
  my %if_pkg_class = map { $_=>1 } split(/\s*,\s*/, $self->option('if_pkg_class') );

  my $allpkgs = (keys %if_pkgpart) ? 0 : 1;

  my @cust_pkg = ();
  if ( $object->table eq 'cust_pkg' ) {

    return 'Package is suspended' if $object->susp;
    return 'Package not selected'
      if ! $allpkgs && ! $if_pkgpart{ $object->pkgpart };
    return 'Package not of selected class'
      if keys %if_pkg_class
      && ! $if_pkg_class{ $object->part_pkg->classnum };
    return 'Package frequency not monthly or a multiple'
      if $object->part_pkg->freq !~ /^\d+$/;

    @cust_pkg = ( $object );

  } else {

    @cust_pkg = grep {
         ( $allpkgs || $if_pkgpart{ $_->pkgpart } ) 
      && ( ! keys %if_pkg_class || $if_pkg_class{ $_->part_pkg->classnum } )
      && $_->part_pkg->freq
      #remove after fixing discount bug with non-monthly pkgs
      && ( $_->part_pkg->freq =~ /^\d+$/)
    }
      $cust_main->unsuspended_pkgs;

    return 'No qualifying packages' unless @cust_pkg;

  }

  my $gotit = 0;
  foreach my $cust_pkg (@cust_pkg) {

    my @cust_pkg_discount = $cust_pkg->cust_pkg_discount_active;

    #our logic here only makes sense insomuch as you can't have multiple discounts
    die "Unexpected multiple discounts, contact developers"
      if scalar(@cust_pkg_discount) > 1;

    my @my_cust_pkg_discount =
      grep { $_->discountnum == $self->option('discountnum') } @cust_pkg_discount;

    if ( @my_cust_pkg_discount ) { #reset the existing one instead

      $gotit = 1;

      #it's already got this discount and discount never expires--great, move on
      unless ( $cust_pkg_discount[0]->discount->months ) {
        if ( $self->option('once_percust') ) {
          last;
        } else {
          next;
        }
      };
	
      #reset the discount
      my $error = $cust_pkg_discount[0]->decrement_months_used( $cust_pkg_discount[0]->months_used );
      die "Error extending discount: $error\n" if $error;

      last if $self->option('once_percust');

    } elsif ( @cust_pkg_discount ) {

      #can't currently discount an already discounted package,
      #but maybe we can discount a different package
      next;

    } else { #normal case, create a new one

      $gotit = 1;
      my $cust_pkg_discount = new FS::cust_pkg_discount {
        'pkgnum'      => $cust_pkg->pkgnum,
        'discountnum' => $self->option('discountnum'),
        'months_used' => 0
      };
      my $error = $cust_pkg_discount->insert;
      die "Error discounting package: $error\n" if $error;

      last if $self->option('once_percust');

    }
  }

  return $gotit ? '' : 'Discount not applied due to existing discounts';

}

1;