001/*
002 * Copyright 2010-2014 Ning, Inc.
003 * Copyright 2014-2018 The Billing Project, LLC
004 *
005 * The Billing Project licenses this file to you under the Apache License, version 2.0
006 * (the "License"); you may not use this file except in compliance with the
007 * License.  You may obtain a copy of the License at:
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017
018package com.ning.billing.recurly.model;
019
020import javax.xml.bind.annotation.XmlElement;
021import javax.xml.bind.annotation.XmlElementWrapper;
022import javax.xml.bind.annotation.XmlRootElement;
023import javax.xml.bind.annotation.XmlTransient;
024
025import org.joda.time.DateTime;
026import com.google.common.base.Objects;
027
028/**
029 * Class that represents the Concept of a Coupon within the Recurly API.
030 */
031@XmlRootElement(name = "coupon")
032public class Coupon extends RecurlyObject {
033    public enum DiscountType {
034        percent, dollars, free_trial
035    }
036
037    public enum Duration {
038        forever, single_use, temporal
039    }
040
041    public enum FreeTrialUnit {
042        day, week, month
043    }
044
045    public enum RedemptionResource {
046        account, subscription
047    }
048
049    public enum TemporalUnit {
050        day, week, month, year;
051    }
052
053    public enum Type {
054        single_code, bulk, unique_code
055    }
056
057    @XmlTransient
058    public static final String COUPON_RESOURCE = "/coupons";
059
060    @XmlTransient
061    public static final String GENERATE_RESOURCE = "/generate";
062
063    @XmlTransient
064    public static final String UNIQUE_CODES_RESOURCE = "/unique_coupon_codes";
065
066    @XmlElement(name = "id")
067    private Long id;
068
069    @XmlElement(name = "name")
070    private String name;
071
072    @XmlElement(name = "coupon_code")
073    private String couponCode;
074
075    /**
076     * Description of the coupon on the hosted payment pages.
077     */
078    @XmlElement(name = "description")
079    private String description;
080
081    /**
082     * Description of the coupon on the invoice.
083     */
084    @XmlElement(name = "invoice_description")
085    private String invoiceDescription;
086
087    /**
088     * Last date to redeem the coupon, defaults to no date
089     */
090    @XmlElement(name = "redeem_by_date")
091    private DateTime redeemByDate;
092
093    /**
094     * Number of months after redemption that the coupon is valid, defaults to no date
095     * @deprecated Please use temporal_unit and temporal_amount
096     */
097    @XmlElement(name = "applies_for_months")
098    private Integer appliesForMonths;
099
100    /**
101     * Maximum number of accounts that may use the coupon before it can no longer be redeemed
102     */
103    @XmlElement(name = "max_redemptions")
104    private Integer maxRedemptions;
105
106    /**
107     * The coupon is valid for all plans if true, defaults to true
108     */
109    @XmlElement(name = "applies_to_all_plans")
110    private Boolean appliesToAllPlans;
111
112    /**
113     * If true, the coupon applies to the first invoice only
114     * @deprecated Please use duration
115     */
116    @XmlElement(name = "single_use")
117    private Boolean singleUse;
118
119    @XmlElement(name = "discount_type")
120    private DiscountType discountType;
121
122    @XmlElement(name = "free_trial_unit")
123    private FreeTrialUnit freeTrialUnit;
124
125    @XmlElement(name = "free_trial_amount")
126    private Integer freeTrialAmount;
127
128    /**
129     * Discount percentage if discount_type is "percent"
130     */
131    @XmlElement(name = "discount_percent")
132    private Integer discountPercent;
133
134    @XmlElement(name = "discount_in_cents")
135    private RecurlyUnitCurrency discountInCents;
136
137    @XmlElement(name = "state")
138    private String state;
139
140    @XmlElement(name = "created_at")
141    private DateTime createdAt;
142
143    @XmlElement(name = "updated_at")
144    private DateTime updatedAt;
145
146    public PlanCodes getPlanCodes() {
147        return planCodes;
148    }
149
150    public void setPlanCodes(final PlanCodes planCodes) {
151        this.planCodes = planCodes;
152    }
153
154    @XmlElement(name = "plan_code")
155    @XmlElementWrapper(name = "plan_codes")
156    private PlanCodes planCodes;
157
158    /**
159     * forever, single_use, or temporal. If single_use, the coupon applies to
160     * the first invoice only. If temporal the coupon will apply to invoices for
161     * the duration determined by the temporal_unit and temporal_amount
162     * attributes.
163     */
164    @XmlElement(name = "duration")
165    private Duration duration;
166
167    /**
168     * day, week, month, or year. If duration is temporal then temporal_unit is
169     * multiplied by temporal_amount to define the duration that the coupon will
170     * be applied to invoices for.
171     */
172    @XmlElement(name = "temporal_unit")
173    private TemporalUnit temporalUnit;
174
175    /**
176     * If duration is temporal then temporal_amount is an integer which is
177     * multiplied by temporal_unit to define the duration that the coupon will
178     * be applied to invoices for.
179     */
180    @XmlElement(name = "temporal_amount")
181    private Integer temporalAmount;
182
183    /**
184     * The coupon is valid for one-time, non-plan charges if true, defaults to
185     * false.
186     */
187    @XmlElement(name = "applies_to_non_plan_charges")
188    private Boolean appliesToNonPlanCharges;
189
190    /**
191     * Whether the discount is for all eligible charges on the account, or only
192     * a specific subscription. Values are account or subscription.
193     */
194    @XmlElement(name = "redemption_resource")
195    private RedemptionResource redemptionResource;
196
197    /**
198     * The number of times the coupon can be redeemed on a specific account
199     */
200    @XmlElement(name = "max_redemptions_per_account")
201    private Integer maxRedemptionsPerAccount;
202
203    /**
204     * Whether the coupon is single_code or bulk. Bulk coupons will require a
205     * unique_code_template and will generate unique codes through the generate
206     * endpoint.
207     */
208    @XmlElement(name = "coupon_type")
209    private Type type;
210
211    /**
212     * The template for generating unique codes.
213     * 
214     * @see <a href=
215     *      "https://dev.recurly.com/docs/create-coupon">https://dev.recurly.com/docs/create-coupon</a>
216     */
217    @XmlElement(name = "unique_code_template")
218    private String uniqueCodeTemplate;
219
220    /**
221     * The number of unique codes to generate.
222     *
223     * @see <a href=
224     *      "https://dev.recurly.com/docs/generate-unique-codes">https://dev.recurly.com/docs/generate-unique-codes</a>
225     */
226    @XmlElement(name = "number_of_unique_codes")
227    private Integer numberOfUniqueCodes;
228
229    public void setId(final Object id) {
230        this.id = longOrNull(id);
231    }
232
233    public Long getId() {
234        return this.id;
235    }
236
237    public String getState() {
238        return state;
239    }
240
241    public void setState(final Object state) {
242        this.state = stringOrNull(state);
243    }
244
245    /**
246     * Gets the name of the {@link Coupon}
247     *
248     * @return The {@link Coupon} name
249     */
250    public String getName() {
251        return name;
252    }
253
254    /**
255     * Sets the name of the {@link Coupon}
256     *
257     * @param name The Name that is to be given to the {@link Coupon}
258     */
259    public void setName(final Object name) {
260        this.name = stringOrNull(name);
261    }
262
263    /**
264     * Gets the coupon code for a {@link Coupon}
265     *
266     * @return The coupon code for the {@link Coupon}
267     */
268    public String getCouponCode() {
269        return couponCode;
270    }
271
272    /**
273     * Sets the coupon code for the {@link Coupon}
274     *
275     * @param couponCode The coupon code
276     */
277    public void setCouponCode(final Object couponCode) {
278        this.couponCode = stringOrNull(couponCode);
279    }
280
281    /**
282     * Sets the discount type for a {@link Coupon}
283     *
284     * @param discountType
285     */
286    public void setDiscountType(final Object discountType) {
287        this.discountType = enumOrNull(DiscountType.class, discountType);
288    }
289
290    /**
291     * Gets the discount type associated with the {@link Coupon}
292     *
293     * @return the DiscountType
294     */
295    public DiscountType getDiscountType() {
296        return discountType;
297    }
298
299    /**
300     * Gets the percentage discount for a coupon
301     *
302     * @return The percentage
303     */
304    public Integer getDiscountPercent() {
305        return discountPercent;
306    }
307
308    public void setDiscountPercent(final Object discountPercent) {
309        this.discountPercent = integerOrNull(discountPercent);
310    }
311
312    public DateTime getRedeemByDate() {
313        return redeemByDate;
314    }
315
316    public void setRedeemByDate(final Object redeemByDate) {
317        this.redeemByDate = dateTimeOrNull(redeemByDate);
318    }
319
320    public Integer getAppliesForMonths() {
321        return appliesForMonths;
322    }
323
324    public void setAppliesForMonths(final Object appliesForMonths) {
325        this.appliesForMonths = integerOrNull(appliesForMonths);
326    }
327
328    public Integer getMaxRedemptions() {
329        return maxRedemptions;
330    }
331
332    public void setMaxRedemptions(final Object maxRedemptions) {
333        this.maxRedemptions = integerOrNull(maxRedemptions);
334    }
335
336    public Boolean getSingleUse() {
337        return singleUse;
338    }
339
340    public void setSingleUse(final Object singleUse) {
341        this.singleUse = booleanOrNull(singleUse);
342    }
343
344    public RecurlyUnitCurrency getDiscountInCents() {
345        return discountInCents;
346    }
347
348    public void setDiscountInCents(final Object discountInCents) {
349        this.discountInCents = RecurlyUnitCurrency.build(discountInCents);
350    }
351
352    public Boolean getAppliesToAllPlans() {
353        return appliesToAllPlans;
354    }
355
356    public void setAppliesToAllPlans(final Object appliesToAllPlans) {
357        this.appliesToAllPlans = booleanOrNull(appliesToAllPlans);
358    }
359
360    public FreeTrialUnit getFreeTrialUnit() {
361        return freeTrialUnit;
362    }
363
364    public void setFreeTrialUnit(final Object freeTrialUnit) {
365        this.freeTrialUnit = enumOrNull(FreeTrialUnit.class, freeTrialUnit);
366    }
367
368    public Integer getFreeTrialAmount() {
369        return freeTrialAmount;
370    }
371
372    public void setFreeTrialAmount(final Object freeTrialAmount) {
373        this.freeTrialAmount = integerOrNull(freeTrialAmount);
374    }
375
376    public DateTime getCreatedAt() {
377        return createdAt;
378    }
379
380    public void setCreatedAt(final Object createdAt) {
381        this.createdAt = dateTimeOrNull(createdAt);
382    }
383
384    public DateTime getUpdatedAt() {
385        return updatedAt;
386    }
387
388    public void setUpdatedAt(final Object updatedAt) {
389        this.updatedAt = dateTimeOrNull(updatedAt);
390    }
391
392    public String getDescription() {
393      return description;
394    }
395
396    public void setDescription(Object description) {
397      this.description = stringOrNull(description);
398    }
399
400    public String getInvoiceDescription() {
401      return invoiceDescription;
402    }
403
404    public void setInvoiceDescription(Object invoiceDescription) {
405      this.invoiceDescription = stringOrNull(invoiceDescription);
406    }
407
408    public Duration getDuration() {
409      return duration;
410    }
411
412    public void setDuration(Object duration) {
413      this.duration = enumOrNull(Duration.class, duration);
414    }
415
416    public TemporalUnit getTemporalUnit() {
417      return temporalUnit;
418    }
419
420    public void setTemporalUnit(Object temporalUnit) {
421      this.temporalUnit = enumOrNull(TemporalUnit.class, temporalUnit);
422    }
423
424    public Integer getTemporalAmount() {
425      return temporalAmount;
426    }
427
428    public void setTemporalAmount(Object temporalAmount) {
429      this.temporalAmount = integerOrNull(temporalAmount);
430    }
431
432    public Boolean getAppliesToNonPlanCharges() {
433      return appliesToNonPlanCharges;
434    }
435
436    public void setAppliesToNonPlanCharges(Object appliesToNonPlanCharges) {
437      this.appliesToNonPlanCharges = booleanOrNull(appliesToNonPlanCharges);
438    }
439
440    public RedemptionResource getRedemptionResource() {
441      return redemptionResource;
442    }
443
444    public void setRedemptionResource(Object redemptionResource) {
445      this.redemptionResource = enumOrNull(RedemptionResource.class, redemptionResource);
446    }
447
448    public Integer getMaxRedemptionsPerAccount() {
449      return maxRedemptionsPerAccount;
450    }
451
452    public void setMaxRedemptionsPerAccount(Object maxRedemptionsPerAccount) {
453      this.maxRedemptionsPerAccount = integerOrNull(maxRedemptionsPerAccount);
454    }
455
456    public Type getType() {
457      return type;
458    }
459
460    public void setType(Type type) {
461      this.type = enumOrNull(Type.class, type);
462    }
463
464    public String getUniqueCodeTemplate() {
465      return uniqueCodeTemplate;
466    }
467
468    public void setUniqueCodeTemplate(Object uniqueCodeTemplate) {
469      this.uniqueCodeTemplate = stringOrNull(uniqueCodeTemplate);
470    }
471
472    public Integer getNumberOfUniqueCodes() {
473        return numberOfUniqueCodes;
474    }
475
476    public void setNumberOfUniqueCodes(Integer numberOfUniqueCodes) {
477        this.numberOfUniqueCodes = numberOfUniqueCodes;
478    }
479
480    @Override
481    public String toString() {
482        final StringBuilder sb = new StringBuilder();
483        sb.append("Coupon");
484        sb.append("{name='").append(name).append('\'');
485        sb.append(", id=").append(id);
486        sb.append(", couponCode='").append(couponCode).append('\'');
487        sb.append(", discountType='").append(discountType).append('\'');
488        sb.append(", discountPercent='").append(discountPercent).append('\'');
489        sb.append(", createdAt=").append(createdAt);
490        sb.append(", updatedAt=").append(updatedAt);
491        sb.append('}');
492        return sb.toString();
493    }
494
495    @Override
496    public boolean equals(final Object o) {
497        if (this == o) return true;
498        if (o == null || getClass() != o.getClass()) return false;
499
500        final Coupon coupon = (Coupon) o;
501
502        if (appliesForMonths != null ? !appliesForMonths.equals(coupon.appliesForMonths) : coupon.appliesForMonths != null) {
503            return false;
504        }
505        if (appliesToNonPlanCharges != null ? !appliesToNonPlanCharges.equals(coupon.appliesToNonPlanCharges) : coupon.appliesToNonPlanCharges != null) {
506            return false;
507        }
508        if (appliesToAllPlans != null ? !appliesToAllPlans.equals(coupon.appliesToAllPlans) : coupon.appliesToAllPlans != null) {
509            return false;
510        }
511        if (couponCode != null ? !couponCode.equals(coupon.couponCode) : coupon.couponCode != null) {
512            return false;
513        }
514        if (planCodes != null ? !planCodes.equals(coupon.planCodes) : coupon.planCodes != null) {
515            return false;
516        }
517        if (createdAt != null ? createdAt.compareTo(coupon.createdAt) != 0 : coupon.createdAt != null) {
518            return false;
519        }
520        if (description != null ? !description.equals(coupon.description) : coupon.description != null) {
521            return false;
522        }
523        if (discountInCents != null ? !discountInCents.equals(coupon.discountInCents) : coupon.discountInCents != null) {
524            return false;
525        }
526        if (discountPercent != null ? !discountPercent.equals(coupon.discountPercent) : coupon.discountPercent != null) {
527            return false;
528        }
529        if (discountType != null ? !discountType.equals(coupon.discountType) : coupon.discountType != null) {
530            return false;
531        }
532        if (duration != null ? !duration.equals(coupon.duration) : coupon.duration != null) {
533            return false;
534        }
535        if (id != null ? !id.equals(coupon.id) : coupon.id != null) {
536            return false;
537        }
538        if (invoiceDescription != null ? !invoiceDescription.equals(coupon.invoiceDescription) : coupon.invoiceDescription != null) {
539            return false;
540        }
541        if (maxRedemptions != null ? !maxRedemptions.equals(coupon.maxRedemptions) : coupon.maxRedemptions != null) {
542            return false;
543        }
544        if (name != null ? !name.equals(coupon.name) : coupon.name != null) {
545            return false;
546        }
547        if (redeemByDate != null ? redeemByDate.compareTo(coupon.redeemByDate) != 0 : coupon.redeemByDate != null) {
548            return false;
549        }
550        if (redemptionResource != null ? redemptionResource.compareTo(coupon.redemptionResource) != 0 : coupon.redemptionResource != null) {
551            return false;
552        }
553        if (singleUse != null ? singleUse.compareTo(coupon.singleUse) != 0 : coupon.singleUse != null) {
554            return false;
555        }
556        if (temporalAmount != null ? temporalAmount.compareTo(coupon.temporalAmount) != 0 : coupon.temporalAmount != null) {
557            return false;
558        }
559        if (temporalUnit != null ? temporalUnit.compareTo(coupon.temporalUnit) != 0 : coupon.temporalUnit != null) {
560            return false;
561        }
562        if (type != null ? type.compareTo(coupon.type) != 0 : coupon.type != null) {
563            return false;
564        }
565        if (uniqueCodeTemplate != null ? uniqueCodeTemplate.compareTo(coupon.uniqueCodeTemplate) != 0 : coupon.uniqueCodeTemplate != null) {
566            return false;
567        }
568        if (freeTrialUnit != null ? !freeTrialUnit.equals(coupon.freeTrialUnit) : coupon.freeTrialUnit != null) {
569            return false;
570        }
571        if (freeTrialAmount != null ? !freeTrialAmount.equals(coupon.freeTrialAmount) : coupon.freeTrialAmount != null) {
572            return false;
573        }
574        if (updatedAt != null ? updatedAt.compareTo(coupon.updatedAt) != 0 : coupon.updatedAt != null) {
575            return false;
576        }
577
578        return true;
579    }
580
581    @Override
582    public int hashCode() {
583        return Objects.hashCode(
584                appliesForMonths,
585                appliesToAllPlans,
586                appliesToNonPlanCharges,
587                name,
588                couponCode,
589                planCodes,
590                description,
591                discountType,
592                discountPercent,
593                discountInCents,
594                duration,
595                id,
596                invoiceDescription,
597                redeemByDate,
598                singleUse,
599                maxRedemptions,
600                freeTrialUnit,
601                freeTrialAmount,
602                createdAt,
603                redemptionResource,
604                temporalAmount,
605                temporalUnit,
606                type,
607                uniqueCodeTemplate,
608                updatedAt
609        );
610    }
611}