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