Преглед на файлове

WIP. adding promotions

tags/v0.7.2
Jonathan Cobb преди 5 години
родител
ревизия
4676bcfeb9
променени са 14 файла, в които са добавени 402 реда и са изтрити 17 реда
  1. +1
    -1
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +12
    -0
      bubble-server/src/main/java/bubble/cloud/payment/PromotionalPaymentServiceDriver.java
  3. +33
    -0
      bubble-server/src/main/java/bubble/cloud/payment/firstMonthFree/FirstMonthFreePaymentDriver.java
  4. +3
    -0
      bubble-server/src/main/java/bubble/cloud/payment/firstMonthFree/FirstMonthPaymentConfig.java
  5. +47
    -0
      bubble-server/src/main/java/bubble/cloud/payment/referralMonthFree/ReferralMonthFreePaymentDriver.java
  6. +3
    -0
      bubble-server/src/main/java/bubble/cloud/payment/referralMonthFree/ReferralMonthPaymentConfig.java
  7. +51
    -0
      bubble-server/src/main/java/bubble/dao/bill/PromotionDAO.java
  8. +24
    -12
      bubble-server/src/main/java/bubble/model/bill/AccountPlan.java
  9. +1
    -1
      bubble-server/src/main/java/bubble/model/bill/PaymentMethodType.java
  10. +73
    -0
      bubble-server/src/main/java/bubble/model/bill/Promotion.java
  11. +56
    -3
      bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java
  12. +4
    -0
      bubble-server/src/main/java/bubble/resources/bill/AllPaymentMethodsResource.java
  13. +87
    -0
      bubble-server/src/main/java/bubble/resources/bill/PromotionsResource.java
  14. +7
    -0
      bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties

+ 1
- 1
bubble-server/src/main/java/bubble/ApiConstants.java Целия файл

@@ -103,7 +103,7 @@ public class ApiConstants {
public static final String CLOUDS_ENDPOINT = "/clouds";
public static final String ROLES_ENDPOINT = "/roles";
public static final String PROXY_ENDPOINT = "/p";
public static final String DATA_ENDPOINT = "/d";
public static final String PROMOTIONS_ENDPOINT = "/promos";

public static final String NOTIFY_ENDPOINT = "/notify";
public static final String EP_READ_METADATA = "/meta";


+ 12
- 0
bubble-server/src/main/java/bubble/cloud/payment/PromotionalPaymentServiceDriver.java Целия файл

@@ -0,0 +1,12 @@
package bubble.cloud.payment;

import bubble.model.account.Account;
import bubble.model.bill.Promotion;

public interface PromotionalPaymentServiceDriver extends PaymentServiceDriver {

void applyPromo(Promotion promo, Account caller);

void applyReferralPromo(Promotion referralPromo, Account caller, Account referredFrom);

}

+ 33
- 0
bubble-server/src/main/java/bubble/cloud/payment/firstMonthFree/FirstMonthFreePaymentDriver.java Целия файл

@@ -0,0 +1,33 @@
package bubble.cloud.payment.firstMonthFree;

import bubble.cloud.payment.PaymentDriverBase;
import bubble.cloud.payment.PromotionalPaymentServiceDriver;
import bubble.model.account.Account;
import bubble.model.bill.*;
import bubble.notify.payment.PaymentValidationResult;

import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;

public class FirstMonthFreePaymentDriver extends PaymentDriverBase<FirstMonthPaymentConfig> implements PromotionalPaymentServiceDriver {

@Override public PaymentMethodType getPaymentMethodType() { return PaymentMethodType.promotional_credit; }

@Override public void applyPromo(Promotion promo, Account caller) {
// todo
}

@Override public void applyReferralPromo(Promotion referralPromo, Account caller, Account referredFrom) { notSupported("applyReferralPromo"); }

@Override public PaymentValidationResult validate(AccountPaymentMethod paymentMethod) {
return null;
}

@Override protected String charge(BubblePlan plan, AccountPlan accountPlan, AccountPaymentMethod paymentMethod, Bill bill) {
return null;
}

@Override protected String refund(AccountPlan accountPlan, AccountPayment payment, AccountPaymentMethod paymentMethod, Bill bill, long refundAmount) {
return null;
}

}

+ 3
- 0
bubble-server/src/main/java/bubble/cloud/payment/firstMonthFree/FirstMonthPaymentConfig.java Целия файл

@@ -0,0 +1,3 @@
package bubble.cloud.payment.firstMonthFree;

public class FirstMonthPaymentConfig {}

+ 47
- 0
bubble-server/src/main/java/bubble/cloud/payment/referralMonthFree/ReferralMonthFreePaymentDriver.java Целия файл

@@ -0,0 +1,47 @@
package bubble.cloud.payment.referralMonthFree;

import bubble.cloud.payment.PaymentDriverBase;
import bubble.cloud.payment.PromotionalPaymentServiceDriver;
import bubble.model.account.Account;
import bubble.model.bill.*;
import bubble.notify.payment.PaymentValidationResult;

import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;

public class ReferralMonthFreePaymentDriver extends PaymentDriverBase<ReferralMonthPaymentConfig> implements PromotionalPaymentServiceDriver {

@Override public PaymentMethodType getPaymentMethodType() { return PaymentMethodType.promotional_credit; }

@Override public void applyPromo(Promotion promo, Account caller) { notSupported("applyPromo"); }

@Override public void applyReferralPromo(Promotion referralPromo, Account caller, Account referredFrom) {
// todo
// validate referralPromo
// check existing AccountPaymentMethods for caller, they can only have one AccountPaymentMethod of the "joiner" type across all methods
// -- create if not exist
// check existing AccountPaymentMethods for referredFrom, they can only have one AccountPaymentMethod of the "referral" type for the caller
// -- create if not exist
}

@Override public PaymentValidationResult validate(AccountPaymentMethod paymentMethod) {
// todo
// validate that this paymentMethod is for this driver
// validate that this paymentMethod has not yet been used on any other AccountPayment
return null;
}

@Override protected String charge(BubblePlan plan, AccountPlan accountPlan, AccountPaymentMethod paymentMethod, Bill bill) {
// todo
// validate that this paymentMethod is for this driver
// validate that this paymentMethod has not yet been used on any other AccountPayment
// apply the paymentMethod
return null;
}

@Override protected String refund(AccountPlan accountPlan, AccountPayment payment, AccountPaymentMethod paymentMethod, Bill bill, long refundAmount) {
// cannot refund
throw invalidEx("err.refund.noRefundsForPromotionalCredits");
}

}

+ 3
- 0
bubble-server/src/main/java/bubble/cloud/payment/referralMonthFree/ReferralMonthPaymentConfig.java Целия файл

@@ -0,0 +1,3 @@
package bubble.cloud.payment.referralMonthFree;

public class ReferralMonthPaymentConfig {}

+ 51
- 0
bubble-server/src/main/java/bubble/dao/bill/PromotionDAO.java Целия файл

@@ -0,0 +1,51 @@
package bubble.dao.bill;

import bubble.model.bill.Promotion;
import org.cobbzilla.wizard.dao.AbstractCRUDDAO;
import org.hibernate.criterion.Order;
import org.springframework.stereotype.Repository;

import java.util.List;

import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.hibernate.criterion.Restrictions.*;

@Repository
public class PromotionDAO extends AbstractCRUDDAO<Promotion> {

public static final Order PRIORITY_DESC = Order.desc("priority");

@Override public Order getDefaultSortOrder() { return PRIORITY_DESC; }

public Promotion findByName(String name) { return findByUniqueField("name", name); }

public Promotion findById(String id) {
final Promotion found = findByUuid(id);
return found != null ? found : findByName(id);
}

public Promotion findEnabledWithCode(String code) {
return findByUniqueFields("enabled", true, "code", code);
}

public Promotion findEnabledWithNoCode() {
final List<Promotion> promos = findByFields("enabled", true, "code", null);
return empty(promos) ? null : promos.get(0);
}

public List<Promotion> findEnabledAndNoCodeOrWithCode(String code) {
if (empty(code)) {
return findByFields("enabled", true, "code", null);
} else {
return list(criteria().add(and(
eq("enabled", true),
or(isNull("code"), eq("code", code)))));
}
}

public Promotion findReferralPromotion() {
final List<Promotion> referrals = findByField("referral", true);
return empty(referrals) ? null : referrals.get(0);
}

}

+ 24
- 12
bubble-server/src/main/java/bubble/model/bill/AccountPlan.java Целия файл

@@ -60,67 +60,79 @@ public class AccountPlan extends IdentifiableBase implements HasAccount {
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

// refers to an Account.uuid, but we do not use a foreign key, so if the referring Account is deleted
// then a lookup of the referralFrom will return null, and any unused referral promotion cannot be used
@ECSearchable @ECField(index=30)
@Column(length=UUID_MAXLEN, updatable=false)
@Getter @Setter private String referralFrom;
public boolean hasReferralFrom () { return !empty(referralFrom); }

@ECSearchable @ECField(index=40)
@Column(length=100, updatable=false)
@Getter @Setter private String promoCode;
public boolean hasPromoCode () { return !empty(promoCode); }

@ECSearchable @ECField(index=50)
@ECForeignKey(entity=BubblePlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String plan;

@ECSearchable @ECField(index=40)
@ECSearchable @ECField(index=60)
@ECForeignKey(entity=AccountPaymentMethod.class)
@Column(updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String paymentMethod;

@ECSearchable @ECField(index=50)
@ECSearchable @ECField(index=70)
@ECForeignKey(entity=BubbleDomain.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String domain;

@ECSearchable @ECField(index=60)
@ECSearchable @ECField(index=80)
@ECForeignKey(entity=BubbleNetwork.class, index=false) @ECIndex(unique=true)
@Column(length=UUID_MAXLEN)
@Getter @Setter private String network;

@ECSearchable @ECField(index=70)
@ECSearchable @ECField(index=90)
@ECForeignKey(entity=AccountSshKey.class)
@Column(length=UUID_MAXLEN)
@Getter @Setter private String sshKey;
public boolean hasSshKey () { return !empty(sshKey); }

@ECSearchable @ECField(index=80)
@ECSearchable @ECField(index=100)
@Column(nullable=false)
@Getter @Setter private Boolean enabled = false;
public boolean enabled() { return bool(enabled); }
public boolean disabled() { return !enabled(); }

@ECSearchable(type=EntityFieldType.epoch_time) @ECField(index=90)
@ECSearchable(type=EntityFieldType.epoch_time) @ECField(index=110)
@Column(nullable=false)
@ECIndex @Getter @Setter private Long nextBill;

@ECSearchable @ECField(index=100)
@ECSearchable @ECField(index=120)
@Column(nullable=false, length=50)
@Getter @Setter private String nextBillDate;
public AccountPlan setNextBillDate() { return setNextBillDate(BILL_START_END_FORMAT.print(getNextBill())); }

@ECSearchable @ECField(index=110)
@ECSearchable @ECField(index=130)
@ECIndex @Getter @Setter private Long deleted;
public boolean deleted() { return deleted != null; }
public boolean notDeleted() { return !deleted(); }

@ECSearchable @ECField(index=120)
@ECSearchable @ECField(index=140)
@Column(nullable=false)
@ECIndex @Getter @Setter private Boolean closed = false;
public boolean closed() { return bool(closed); }
public boolean notClosed() { return !closed(); }

@ECSearchable @ECField(index=130, type=EntityFieldType.reference)
@ECSearchable @ECField(index=150, type=EntityFieldType.reference)
@ECIndex(unique=true) @Column(length=UUID_MAXLEN)
@Getter @Setter private String deletedNetwork;
public boolean hasDeletedNetwork() { return deletedNetwork != null; }

@ECSearchable @ECField(index=140) @Column(nullable=false)
@ECSearchable @ECField(index=160) @Column(nullable=false)
@Getter @Setter private Boolean refundIssued = false;

@ECSearchable @ECField(index=150, type=EntityFieldType.error)
@ECSearchable @ECField(index=170, type=EntityFieldType.error)
@Getter @Setter private String refundError;

// Fields below are used when creating a new plan, to also create the network associated with it


+ 1
- 1
bubble-server/src/main/java/bubble/model/bill/PaymentMethodType.java Целия файл

@@ -6,7 +6,7 @@ import static bubble.ApiConstants.enumFromString;

public enum PaymentMethodType {

credit, code, free;
credit, code, free, promotional_credit;

public boolean requiresClaim() { return this == code; }
public boolean requiresAuth() { return this == credit; }


+ 73
- 0
bubble-server/src/main/java/bubble/model/bill/Promotion.java Целия файл

@@ -0,0 +1,73 @@
package bubble.model.bill;

import bubble.model.cloud.CloudService;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.util.collection.ArrayUtil;
import org.cobbzilla.util.collection.HasPriority;
import org.cobbzilla.wizard.model.Identifiable;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.NamedEntity;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.cobbzilla.wizard.validation.HasValue;

import javax.persistence.Column;
import javax.persistence.Entity;

import static bubble.ApiConstants.PROMOTIONS_ENDPOINT;
import static org.cobbzilla.util.daemon.ZillaRuntime.now;
import static org.cobbzilla.util.reflect.ReflectionUtil.copy;

@ECType(root=true)
@ECTypeURIs(baseURI=PROMOTIONS_ENDPOINT, listFields={"name", "enabled", "start", "end"})
@Entity @NoArgsConstructor @Accessors(chain=true)
public class Promotion extends IdentifiableBase implements NamedEntity, HasPriority {

public static final String[] UPDATE_FIELDS = {"enabled", "start", "end"};
public static final String[] CREATE_FIELDS = ArrayUtil.append(UPDATE_FIELDS, "name", "referral");

public Promotion (Promotion other) { copy(this, other, CREATE_FIELDS); }

@Override public Identifiable update(Identifiable other) { copy(this, other, UPDATE_FIELDS); return this; }

@ECSearchable(filter=true) @ECField(index=10)
@HasValue(message="err.name.required")
@ECIndex(unique=true) @Column(nullable=false, updatable=false, length=NAME_MAXLEN)
@Getter @Setter private String name;

@ECSearchable @ECField(index=20)
@ECForeignKey(entity=CloudService.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String cloud;

@ECSearchable @ECField(index=30) @Column(nullable=false)
@ECIndex @Getter @Setter private Integer priority = 1;

@ECSearchable(filter=true) @ECField(index=40)
@ECIndex(unique=true) @Column(updatable=false, length=NAME_MAXLEN)
@Getter @Setter private String code;

@ECSearchable @ECField(index=50)
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable @ECField(index=60)
@ECIndex @Getter @Setter private Long start;
public boolean hasStarted () { return start == null || start > now(); }

@ECSearchable @ECField(index=70)
@ECIndex @Getter @Setter private Long end;
public boolean hasEnded () { return end != null && end > now(); }

public boolean active () { return enabled() && hasStarted() && !hasEnded(); }
public boolean inactive () { return !active(); }

@ECSearchable @ECField(index=80)
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean referral = false;
public boolean referral () { return referral != null && referral; }

}

+ 56
- 3
bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java Целия файл

@@ -2,19 +2,20 @@ package bubble.resources.bill;

import bubble.cloud.CloudServiceType;
import bubble.cloud.geoLocation.GeoLocation;
import bubble.cloud.payment.PaymentServiceDriver;
import bubble.cloud.payment.PromotionalPaymentServiceDriver;
import bubble.dao.account.AccountSshKeyDAO;
import bubble.dao.bill.AccountPaymentMethodDAO;
import bubble.dao.bill.AccountPlanDAO;
import bubble.dao.bill.BubblePlanDAO;
import bubble.dao.bill.PromotionDAO;
import bubble.dao.cloud.BubbleDomainDAO;
import bubble.dao.cloud.BubbleFootprintDAO;
import bubble.dao.cloud.BubbleNetworkDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.account.Account;
import bubble.model.account.AccountSshKey;
import bubble.model.bill.AccountPaymentMethod;
import bubble.model.bill.AccountPlan;
import bubble.model.bill.BubblePlan;
import bubble.model.bill.*;
import bubble.model.cloud.BubbleDomain;
import bubble.model.cloud.BubbleFootprint;
import bubble.model.cloud.BubbleNetwork;
@@ -57,6 +58,7 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco
@Autowired private BubbleConfiguration configuration;
@Autowired private AuthenticatorService authenticatorService;
@Autowired private GeoService geoService;
@Autowired private PromotionDAO promotionDAO;

public AccountPlansResource(Account account) { super(account); }

@@ -189,6 +191,57 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco
paymentMethod.setAccount(caller.getUuid()).validate(errors, configuration);
}
}
if (request.hasReferralFrom()) {
final Account referredFrom = accountDAO.findByName(request.getReferralFrom());
if (referredFrom == null || referredFrom.deleted()) {
errors.addViolation("err.referralFrom.invalid");
}
// check for referral promotion
final Promotion referralPromo = promotionDAO.findReferralPromotion();
if (referralPromo == null) {
errors.addViolation("err.referralFrom.unavailable");
} else {
final CloudService referralCloud = cloudDAO.findByUuid(referralPromo.getCloud());
if (referralCloud == null || referralCloud.getType() != CloudServiceType.payment) {
errors.addViolation("err.referralFrom.configurationError");
} else {
final PaymentServiceDriver referralDriver = referralCloud.getPaymentDriver(configuration);
if (referralDriver.getPaymentMethodType() != PaymentMethodType.promotional_credit
|| !(referralDriver instanceof PromotionalPaymentServiceDriver)) {
errors.addViolation("err.referralFrom.configurationError");
} else {
final PromotionalPaymentServiceDriver promoDriver = (PromotionalPaymentServiceDriver) referralDriver;
promoDriver.applyReferralPromo(referralPromo, caller, referredFrom);
}
}
}
}
final Promotion promo;
if (request.hasPromoCode()) {
promo = promotionDAO.findEnabledWithCode(request.getPromoCode());
if (promo == null) {
errors.addViolation("err.promoCode.notFound");
} else if (promo.inactive()) {
errors.addViolation("err.promoCode.notActive");
}
} else {
promo = promotionDAO.findEnabledWithNoCode();
}
if (promo != null) {
final CloudService referralCloud = cloudDAO.findByUuid(promo.getCloud());
if (referralCloud == null || referralCloud.getType() != CloudServiceType.payment) {
errors.addViolation("err.promoCode.configurationError");
} else {
final PaymentServiceDriver referralDriver = referralCloud.getPaymentDriver(configuration);
if (referralDriver.getPaymentMethodType() != PaymentMethodType.promotional_credit
|| !(referralDriver instanceof PromotionalPaymentServiceDriver)) {
errors.addViolation("err.promoCode.configurationError");
} else {
final PromotionalPaymentServiceDriver promoDriver = (PromotionalPaymentServiceDriver) referralDriver;
promoDriver.applyPromo(promo, caller);
}
}
}
}
if (errors.isInvalid()) throw invalidEx(errors);



+ 4
- 0
bubble-server/src/main/java/bubble/resources/bill/AllPaymentMethodsResource.java Целия файл

@@ -41,6 +41,7 @@ public class AllPaymentMethodsResource {
for (CloudService cloud : allPaymentServices) {
final PaymentMethodType paymentMethodType = cloud.getPaymentDriver(configuration).getPaymentMethodType();
if (type != null && type != paymentMethodType) continue;
if (paymentMethodType == PaymentMethodType.promotional_credit) continue; // do not include promotions
if (!typesFound.contains(paymentMethodType)) {
paymentServices.add(new PaymentService(cloud, paymentMethodType));
typesFound.add(paymentMethodType);
@@ -60,6 +61,9 @@ public class AllPaymentMethodsResource {
cloud = cloudDAO.findFirstByAccountAndTypeAndDriverClass(account.getUuid(), CloudServiceType.payment, id);
}
if (cloud == null) return notFound(id);
if (cloud.getPaymentDriver(configuration).getPaymentMethodType() == PaymentMethodType.promotional_credit) {
return notFound(id); // cannot find promotions this way
}
return ok(new PaymentService(cloud, cloud.getPaymentDriver(configuration).getPaymentMethodType()));
}



+ 87
- 0
bubble-server/src/main/java/bubble/resources/bill/PromotionsResource.java Целия файл

@@ -0,0 +1,87 @@
package bubble.resources.bill;

import bubble.cloud.CloudServiceType;
import bubble.dao.account.AccountDAO;
import bubble.dao.bill.PromotionDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.account.Account;
import bubble.model.bill.Promotion;
import bubble.model.cloud.CloudService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;

import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Slf4j
public class PromotionsResource {

@Autowired private CloudServiceDAO cloudDAO;
@Autowired private PromotionDAO promotionDAO;
@Autowired private AccountDAO accountDAO;

@Getter(lazy=true) private final Account firstAdmin = accountDAO.getFirstAdmin();

@GET
public Response listPromos(@Context ContainerRequest ctx,
@QueryParam("code") String code) {
final Account caller = optionalUserPrincipal(ctx);
return ok(promotionDAO.findEnabledAndNoCodeOrWithCode(code));
}

@PUT
public Response createPromo(@Context ContainerRequest ctx,
Promotion request) {

final Account caller = userPrincipal(ctx);
if (!caller.admin()) return forbidden();
if (!caller.getUuid().equals(getFirstAdmin().getUuid())) return forbidden();

final Promotion existing = promotionDAO.findByName(request.getName());
if (existing != null) {
return ok(promotionDAO.update((Promotion) existing.update(request)));
} else {
final CloudService cloud = cloudDAO.findByAccountAndTypeAndId(getFirstAdmin().getUuid(), CloudServiceType.payment, request.getCloud());
if (cloud == null) return notFound(request.getCloud());
return ok(promotionDAO.create(request.setCloud(cloud.getUuid())));
}
}

@POST @Path("/{id}")
public Response updatePromo(@Context ContainerRequest ctx,
@PathParam("id") String id,
Promotion request) {

final Account caller = userPrincipal(ctx);
if (!caller.admin()) return forbidden();
if (!caller.getUuid().equals(getFirstAdmin().getUuid())) return forbidden();

final Promotion existing = promotionDAO.findById(id);
if (existing == null) return notFound(id);
return ok(promotionDAO.update((Promotion) existing.update(request)));
}

@DELETE @Path("/{id}")
public Response deletePromo(@Context ContainerRequest ctx,
@PathParam("id") String id) {

final Account caller = userPrincipal(ctx);
if (!caller.admin()) return forbidden();
if (!caller.getUuid().equals(getFirstAdmin().getUuid())) return forbidden();

final Promotion existing = promotionDAO.findById(id);
if (existing == null) return notFound(id);
promotionDAO.delete(existing.getUuid());

return ok_empty();
}

}

+ 7
- 0
bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties Целия файл

@@ -587,6 +587,9 @@ err.price.invalid=Price is invalid
err.price.length=Price is too long
err.privateKeyHash.length=Private key hash is too long
err.privateKey.length=Private key is too long
err.promoCode.notFound=Promo code was not found
err.promoCode.notActive=Promotion is no longer available
err.promoCode.configurationError=Promotion was not set up correctly
err.purchase.accountMismatch=Invalid payment
err.purchase.amountMismatch=Payment amount does not match billed amount
err.purchase.authNotFound=Payment authorization was not found
@@ -612,6 +615,9 @@ err.purchase.declined=Purchase was unsuccessful
err.quantity.length=Quantity is too long
err.region.required=Region is required
err.region.notFound=Region not found
err.referralFrom.invalid=Referral account name is invalid
err.referralFrom.unavailable=No referral program is currently available
err.referralFrom.configurationError=The referral program is not set up correctly
err.refund.billNotFound=Bill not found, cannot refund. Please contact support
err.refund.paymentMethodNotFound=Payment method used for most recent bill not found, cannot refund. Please contact support
err.refund.paymentNotFound=Payment not found for most recent bill, cannot refund. Please contact support
@@ -621,6 +627,7 @@ err.refund.processingError=Error processing credit card refund
err.refund.refundFailedError=Error processing credit card refund, refund failed
err.refund.refundPendingError=Error processing credit card refund, refund is pending
err.refund.unpaidBillHasPayment=Unpaid bill shows payment, not issuing refund. Please contact support
err.refund.noRefundsForPromotionalCredits=Cannot issue refund for promotional credit
err.refund.unknownError=An error occurred processing your refund. Please contact support
err.remoteHost.length=Remote host is too long
err.remoteHost.required=Remote host is required


Зареждане…
Отказ
Запис