<?php
namespace Bidcoz\Bundle\CoreBundle\Entity;
use Bidcoz\Bundle\CoreBundle\Constants;
use Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\Account\Account;
use Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\Account\OrganizationAccount;
use Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\PaymentGateway;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serialize;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @ORM\Entity(repositoryClass="OrganizationRepository")
*
* @ORM\Table(
* name="organizations",
* uniqueConstraints={
*
* @ORM\UniqueConstraint(name="organization_slug_uk",columns={"slug"})
* }
* )
*
* @Serialize\ExclusionPolicy("all")
*/
class Organization implements Themeable, \JsonSerializable
{
public const BIDCOZ_ORG_ID = 1;
public const DEFAULT_MANDRILL_SUBACCOUNT = 'default';
public const CAUSEPILOT_TWILIO_ACCOUNT = 'causepilot';
public const FLIGHT_SIMULATOR_STATUS_READY = 0;
public const FLIGHT_SIMULATOR_STATUS_RESETTING = 1;
public const FLIGHT_SIMULATOR_STATUS_ERROR = 2;
public const FLIGHT_SIMULATOR_STATUS_RESETTING_DONE = 3;
private const DEFAULT_COMMISSION = 0.05;
private const DEFAULT_SERVICE_FEES_CAP = 1997;
/**
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(name="name", type="text", nullable=true)
*
* @Serialize\Expose
*
* @Serialize\Groups({"Default", "API"})
*/
protected ?string $name = null;
/**
* @ORM\Column(name="slug", type="string", length=50);
*
* @Assert\NotBlank
*
* @Assert\Regex(pattern="/^[0-9a-z-]+$/i", message="Organization URL can only contain lower-case letters, numbers and dashes")
*
* @Assert\Length(min=3)
*
* @Serialize\Expose
*
* @Serialize\Groups({"Default", "API"})
*/
protected $slug;
/**
* @ORM\OneToMany(targetEntity="Campaign", mappedBy="organization")
*/
protected $campaigns;
/**
* @ORM\Column(name="active", type="boolean");
*/
protected $active = true;
/**
* @ORM\Column(name="approved", type="boolean");
*/
protected $approved = true;
/**
* @ORM\Column(name="commission", type="float");
*/
protected $commission = self::DEFAULT_COMMISSION;
/**
* @ORM\Column(name="enable_customizations", type="boolean");
*/
protected $enableCustomizations = false;
/**
* @ORM\Column(name="non_profit", type="boolean");
*/
protected $nonProfit = false;
/**
* @ORM\Column(name="service_fees_cap", type="decimal", scale=2, precision=10)
*
* @Assert\NotBlank
*/
protected float $serviceFeesCap = 0.0;
/**
* @ORM\Column(name="total_service_fees", type="decimal", scale=2, precision=10)
*
* @Assert\NotBlank
*/
protected float $totalServiceFees = 0.0;
/**
* @ORM\Column(name="total_service_fees_capped", type="decimal", scale=2, precision=10)
*
* @Assert\NotBlank
*/
protected float $totalServiceFeesCapped = 0.0;
/**
* @ORM\Column(name="plan_renewal_amount", type="decimal", scale=2, precision=10)
*/
protected float $planRenewalAmount = 0.0;
/**
* @ORM\Column(name="tin", type="string", nullable=true);
*
* @Serialize\Expose
*/
protected $tin;
/**
* @ORM\OneToMany(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\Account\OrganizationAccount", mappedBy="organization")
*
* @Assert\Valid
*/
protected $paymentGatewayAccounts;
/**
* @var Collection|OrganizationAdmin[]|null
* @ORM\OneToMany(targetEntity="OrganizationAdmin", mappedBy="organization")
* @ORM\OrderBy({"createdAt" = "ASC"})
*/
protected ?Collection $admins;
/**
* @ORM\Embedded(class="Theme", columnPrefix="org_")
*
* @Assert\Valid
*/
protected ?Theme $theme = null;
/**
* @ORM\ManyToOne(targetEntity="Image")
*
* @ORM\JoinColumn(name="banner_image_id", referencedColumnName="id", onDelete="SET NULL")
*
* @Serialize\Expose
*/
protected ?Image $bannerImage = null;
/**
* @ORM\ManyToOne(targetEntity="Image")
*
* @ORM\JoinColumn(name="logo_image_id", referencedColumnName="id", onDelete="SET NULL")
*
* @Serialize\Expose
*/
protected ?Image $logo = null;
/**
* @ORM\Column(name="url_editable_until", type="datetime")
*/
protected $urlEditableUntil;
/**
* @ORM\Column(name="created_at", type="datetime")
*
* @Serialize\Expose
*/
protected $createdAt;
/**
* @ORM\Column(name="admin_org", type="boolean");
*/
protected $adminOrg = false;
/**
* @ORM\Column(name="stripe_address_check", type="boolean");
*/
protected $stripeAddressCheck = false;
/**
* @ORM\Column(name="mandrill_subaccount", type="string", length=50, nullable=true);
*/
protected $mandrillAccount = self::DEFAULT_MANDRILL_SUBACCOUNT;
/**
* @ORM\Column(name="currency", type="string", length=3);
*/
protected $currency = 'USD';
/**
* @var Address
*
* @ORM\Embedded(class= "Bidcoz\Bundle\CoreBundle\Entity\Address", columnPrefix=false)
*
* @Assert\Valid
*
* @Serialize\Expose
*/
protected $address;
/**
* @ORM\Column(name="phone", type="string", nullable=true);
*
* @Serialize\Expose
*/
protected $phone;
/**
* @ORM\Column(name="contact_name", type="string", nullable=true);
*
* @Assert\Length(max=255)
*
* @Serialize\Expose
*/
protected $contactName;
/**
* @ORM\Column(name="contact_email", type="string", nullable=true);
*
* @Assert\Length(max=255)
*
* @Assert\Email()
*
* @Serialize\Expose
*/
protected $contactEmail;
// Not mapped, a hack around the registration form
protected $acceptTerms;
/**
* @ORM\Column(name="notes", type="text", nullable=true);
*/
protected $notes;
/**
* @ORM\Column(name="no_payment_gateway_required", type="boolean", options={"default"= false});
*/
protected $paymentGatewayNotRequired = false;
/**
* @ORM\Column(name="kindful_token", length=64, type="string", nullable=true);
*/
protected $kindfulToken;
/**
* @ORM\Column(name="stripe_subscription_id", type="string", nullable=true, length=50);
*/
protected $stripeSubscriptionId;
/**
* @ORM\ManyToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\CreditCard")
*
* @ORM\JoinColumn(name="card_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $creditCard;
/**
* @ORM\ManyToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\TwilioAccount")
*
* @ORM\JoinColumn(name="twilio_account", referencedColumnName="id", nullable=false)
*
* @Assert\NotNull
*/
protected $twilioAccount;
/**
* @ORM\Column(type="string", length=100, nullable=true, name="web_address")
*/
protected $webAddress;
/**
* @ORM\Column(type="string", length=100, nullable=true, name="organization_type")
*/
protected $organizationType;
/**
* @ORM\OneToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\TaxCertificate", cascade={"remove"})
*
* @Serialize\Expose
*/
protected ?TaxCertificate $taxCertificate = null;
/**
* @var TaxCertificate[]|Collection|null
*
* @ORM\OneToMany(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\TaxCertificate", mappedBy="organization", cascade={"remove"})
*
* @Serialize\Expose
*/
protected ?Collection $taxCertificates = null;
/**
* @ORM\Column(type="boolean", options={"default": false})
*/
private bool $nonProfitApproved = false;
/**
* @ORM\Column(name="flight_simulator_status", type="integer", nullable=true);
*/
protected ?int $flightSimulatorStatus = self::FLIGHT_SIMULATOR_STATUS_READY;
public function __construct()
{
$this->campaigns = new ArrayCollection();
$this->paymentGatewayAccounts = new ArrayCollection();
$this->admins = new ArrayCollection();
$this->theme = new Theme();
$this->urlEditableUntil = new \DateTime('+7 days');
$this->createdAt = new \DateTime();
}
public function __clone()
{
$this->id = null;
$this->mandrillAccount = self::DEFAULT_MANDRILL_SUBACCOUNT;
}
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getName(): ?string
{
return $this->name;
}
public function setSlug($slug)
{
$this->slug = $slug;
}
public function ensureSlugLowercase()
{
$this->slug = strtolower($this->slug);
}
public function getSlug()
{
return $this->slug;
}
public function getOrganizationType()
{
return $this->organizationType;
}
public function setOrganizationType($organizationType)
{
$this->organizationType = $organizationType;
if ($organizationType == 'non-profit') {
$this->setNonProfit(true);
}
}
/**
* @return Collection|Campaign[]
*/
public function getCampaigns(bool $activeOnly = false, bool $returnLocked = true): Collection
{
if (!$activeOnly) {
return $this->campaigns;
}
return $this->campaigns->filter(function (Campaign $campaign) use ($returnLocked) {
if (!$returnLocked && $campaign->isLocked()) {
return false;
}
return $campaign->isActive();
});
}
public function getAdminSortedCampaigns()
{
$campaigns = $this->campaigns->toArray();
usort($campaigns, function (Campaign $a, Campaign $b) {
if ($a->isHidden() != $b->isHidden()) {
return $a->isHidden() ? 1 : -1;
}
if ($a->isLocked() != $b->isLocked()) {
return $a->isLocked() ? 1 : -1;
}
return $a->getName() <=> $b->getName();
});
return $campaigns;
}
public function getCampaignBySlug($slug): ?Campaign
{
$result = null;
foreach ($this->getCampaigns() as $campaign) {
if ($campaign->getSlug() === $slug) {
$result = $campaign;
break;
}
}
return $result;
}
public function setActive($active)
{
$this->active = $active;
}
public function isActive()
{
return $this->active;
}
public function setStripeAddressCheck($stripeAddressCheck)
{
$this->stripeAddressCheck = $stripeAddressCheck;
}
public function isStripeAddressCheck()
{
return $this->stripeAddressCheck;
}
public function setApproved($approved)
{
$this->approved = $approved;
}
public function isApproved()
{
return $this->approved;
}
public function isPendingVerification()
{
return $this->isActive()
&& $this->isApproved()
&& $this->isNonprofit()
&& 0 == $this->getServiceFeesCap();
}
public function setTin($tin)
{
$this->tin = $tin;
}
public function getTin()
{
return $this->tin;
}
public function setStripeSubscriptionId(?string $subscriptionId)
{
$this->stripeSubscriptionId = $subscriptionId;
}
public function getStripeSubscriptionId(): ?string
{
return $this->stripeSubscriptionId;
}
public function setCreditCard(CreditCard $cc)
{
$this->creditCard = $cc;
}
public function getCreditCard(): ?CreditCard
{
return $this->creditCard;
}
public function isStripeAllowed(): bool
{
return true;
}
public function getPaymentGatewayChoices()
{
return [
'Stripe' => PaymentGateway::STRIPE,
];
}
public function clearPaymentGatewayAccounts()
{
$this->paymentGatewayAccounts = new ArrayCollection();
}
public function addPaymentGatewayAccount(OrganizationAccount $account)
{
if (!$this->paymentGatewayAccounts->contains($account)) {
$this->paymentGatewayAccounts->add($account);
}
}
public function hasPaymentGatewayAccount(Account $account)
{
return $this->paymentGatewayAccounts->exists(function ($index, $orgAccount) use ($account) {
return $account == $orgAccount->getAccount();
});
}
public function hasPaymentGatewayAccountType($type)
{
return $this->paymentGatewayAccounts->exists(function ($index, $orgAccount) use ($type) {
return $orgAccount->getAccount()->getType() == $type;
});
}
public function getPaymentGatewayAccount($type)
{
$orgAccount = $this->paymentGatewayAccounts->filter(function ($orgAccount) use ($type) {
return $orgAccount->getAccount()->getType() == $type;
})->first();
if ($orgAccount) {
return $orgAccount->getAccount();
}
}
public function getPaymentGatewayAccounts()
{
return $this->paymentGatewayAccounts;
}
/**
* @Assert\IsTrue(message="You must connect to Stripe to accept payments.", groups={"payment"})
*/
public function hasPaymentGateway(): bool
{
if ($this->paymentGatewayNotRequired) {
return true;
}
if ($this->isStripeAllowed()) {
return (bool) $this->getPaymentGatewayAccount(Account::STRIPE);
} else {
return count($this->getPaymentGatewayAccounts()) > 0;
}
}
public function setTheme(?Theme $theme)
{
$this->theme = $theme;
}
public function getTheme()
{
return $this->theme;
}
public function setBannerImage(?Image $image)
{
$this->bannerImage = $image;
}
public function removeBannerImage()
{
$this->bannerImage = null;
}
public function getBannerImage()
{
return $this->bannerImage;
}
public function setLogo(Image $image = null)
{
$this->logo = $image;
}
public function getLogo()
{
return $this->logo;
}
public function removeLogo()
{
$this->logo = null;
}
public function getUrlEditableUntil()
{
return $this->urlEditableUntil;
}
public function setUrlEditableUntil($urlEditableUntil)
{
$this->urlEditableUntil = $urlEditableUntil;
}
public function isUrlEditable()
{
$now = new \DateTime();
return $now < $this->urlEditableUntil;
}
public function getCreatedAt()
{
return $this->createdAt;
}
public function setAcceptTerms($acceptTerms)
{
$this->acceptTerms = $acceptTerms;
}
/**
* @Assert\IsTrue(message="You must accept the Organization (non-profit) Terms of Use")
*/
public function getAcceptTerms()
{
return $this->acceptTerms;
}
public function setAdminOrg($adminOrg)
{
$this->adminOrg = $adminOrg;
}
public function isAdminOrg()
{
return $this->adminOrg;
}
public function setMandrillAccount($account)
{
$this->mandrillAccount = $account;
}
public function getMandrillAccount()
{
return $this->mandrillAccount;
}
public function isDefaultSubaccount()
{
return self::DEFAULT_MANDRILL_SUBACCOUNT == $this->mandrillAccount;
}
public function setCurrency($currency)
{
$this->currency = $currency;
}
public function getCurrency()
{
return $this->currency;
}
public static function getOrganizationTypeChoices()
{
return array_flip([
'individual' => 'Individual',
'group' => 'Group',
'non-profit' => 'Non-Profit Organization',
]);
}
public static function getCurrencyChoices()
{
return array_flip([
'USD' => 'US Dollar ($)',
'SGD' => 'Singapore Dollar ($)',
'AUD' => 'Australian Dollar ($)',
'NZD' => 'New Zealand Dollar ($)',
]);
}
public function getCurrencyDisplay(): string
{
return array_flip(self::getCurrencyChoices())[$this->currency];
}
public function setAddress(Address $address)
{
$this->address = $address;
}
public function getAddress()
{
return $this->address;
}
public function setPhone($phone)
{
$this->phone = $phone;
}
public function getPhone()
{
return $this->phone;
}
public function setContactName($contactName)
{
$this->contactName = $contactName;
}
public function getContactName()
{
return $this->contactName;
}
public function setContactEmail($contactEmail)
{
$this->contactEmail = $contactEmail;
}
public function getContactEmail()
{
return $this->contactEmail;
}
/**
* @Assert\Callback
*/
public function isReservedSlug(ExecutionContextInterface $context)
{
if (in_array($this->slug, $this->getReservedSlugs()) || !preg_match('#'.Constants::RESERVED_SLUG_REGEX.'#', $this->slug)) {
$context->buildViolation('This is a reserved url.')
->atPath('slug')
->addViolation();
return true;
}
return false;
}
public static function getReservedSlugs()
{
$strLen = strlen(Constants::RESERVED_SLUG_REGEX);
$lastWord = strpos(Constants::RESERVED_SLUG_REGEX, '))');
$slugStr = substr(Constants::RESERVED_SLUG_REGEX, 6, ($strLen - $lastWord) * -1);
return array_merge(explode('|', $slugStr), [
'organization',
'manage',
'home',
'login_check',
'dashboard',
'account',
'legal',
'payment',
'terms',
'email',
'admin',
'login',
]);
}
public function setNotes(string $notes)
{
$this->notes = $notes;
}
public function getNotes()
{
return $this->notes;
}
public function getCustomDomain()
{
if ('nvidia' === $this->slug) {
return 'nvidia.causepilot.com';
} elseif ('chg' === $this->slug) {
return 'chg.causepilot.com';
}
}
public function isAuctionItemShareable(): bool
{
return !$this->isEnableCustomizations();
}
public function getKindfulToken()
{
return $this->kindfulToken;
}
public function setKindfulToken($token)
{
$this->kindfulToken = $token;
}
public function getAdmins(): ?Collection
{
return $this->admins;
}
public function setAdmins(Collection $admins): Organization
{
$this->admins = $admins;
return $this;
}
public function setTwilioAccount(TwilioAccount $twilioAccount)
{
$this->twilioAccount = $twilioAccount;
}
public function getTwilioAccount(): TwilioAccount
{
return $this->twilioAccount;
}
public function isEnableCustomizations(): bool
{
return $this->enableCustomizations;
}
public function setEnableCustomizations(bool $enableCustomizations)
{
$this->enableCustomizations = $enableCustomizations;
}
public function getCommission(): float
{
return $this->commission;
}
public function setCommission(float $commission)
{
$this->commission = $commission;
}
public function setDefaultCommission()
{
$this->commission = self::DEFAULT_COMMISSION;
}
public function isNonprofit(): bool
{
return $this->nonProfit;
}
public function setNonProfit(bool $nonProfit)
{
$this->nonProfit = $nonProfit;
}
public function delayServiceFeeCalculation(): bool
{
return $this->slug === 'chg';
}
public function getServiceFeesCap(): ?float
{
return $this->serviceFeesCap;
}
public function setServiceFeesCap(?float $serviceFeesCap): void
{
$this->serviceFeesCap = $serviceFeesCap;
}
public function getTotalServiceFees(): ?float
{
return $this->totalServiceFees;
}
public function setTotalServiceFees(?float $totalServiceFees): void
{
$this->totalServiceFees = $totalServiceFees;
}
public function getTotalServiceFeesCapped(): ?float
{
return $this->totalServiceFeesCapped;
}
public function setTotalServiceFeesCapped(?float $totalServiceFeesCapped): void
{
$this->totalServiceFeesCapped = $totalServiceFeesCapped;
}
public function setDefaultServiceFeesCap()
{
$this->serviceFeesCap = self::DEFAULT_SERVICE_FEES_CAP;
}
public function getPlanRenewalAmount(): float
{
return $this->planRenewalAmount;
}
public function setPlanRenewalAmount(float $planRenewalAmount): void
{
$this->planRenewalAmount = $planRenewalAmount;
}
public function isAutoCreateTransactionForExternalPurchases(): bool
{
// Can make a db flag later if needed
return 'chg' === $this->slug;
}
public function getWebAddress()
{
return $this->webAddress;
}
public function setWebAddress(string $webAddress)
{
$this->webAddress = $webAddress;
}
public function addTaxCertificate(TaxCertificate $taxCertificate): void
{
$this->taxCertificates->add($taxCertificate);
$this->setTaxCertificate($taxCertificate);
}
public function removeTaxCertificate(TaxCertificate $taxCertificate): void
{
$this->taxCertificates->removeElement($taxCertificate);
if ($this->taxCertificate === $taxCertificate) {
$this->setTaxCertificate(null);
}
}
public function getTaxCertificate(): ?TaxCertificate
{
return $this->taxCertificate;
}
public function setTaxCertificate(?TaxCertificate $taxCertificate): self
{
$this->taxCertificate = $taxCertificate;
return $this;
}
public function getTaxCertificates(): ?Collection
{
return $this->taxCertificates;
}
public function setTaxCertificates(?Collection $taxCertificates): self
{
$this->taxCertificates = $taxCertificates;
return $this;
}
public function hasTaxCertificate(): bool
{
return null !== $this->taxCertificate;
}
public function getFlightSimulatorStatus(): ?int
{
return $this->flightSimulatorStatus;
}
public function setFlightSimulatorStatus(int $flightSimulatorStatus): void
{
$this->flightSimulatorStatus = $flightSimulatorStatus;
}
public function jsonSerialize()
{
return [
'name' => $this->getName(),
'logo' => $this->getLogo(),
];
}
public function isNonProfitApproved(): bool
{
return $this->nonProfitApproved;
}
public function setNonProfitApproved(bool $nonProfitApproved): self
{
$this->nonProfitApproved = $nonProfitApproved;
return $this;
}
}