<?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\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
{
const BIDCOZ_ORG_ID = 1;
const PAYMENT_MODEL_BIDCOZ = 'bidcoz';
const PAYMENT_MODEL_ORGANIZATION = 'organization';
const DEFAULT_MANDRILL_SUBACCOUNT = 'default';
const CAUSEPILOT_TWILIO_ACCOUNT = 'causepilot';
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(name="name", type="text")
* @Assert\NotBlank
* @Assert\Length(min=3)
* @Serialize\Expose
* @Serialize\Groups({"Default", "API"})
*/
protected $name;
/**
* @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 = false;
/**
* @ORM\Column(name="enterprise", type="boolean");
*/
protected $enterprise = false;
/**
* @ORM\Column(name="directory_only", type="boolean");
*/
protected $directoryOnly = false;
/**
* @ORM\Column(name="tin", type="string", nullable=true);
* @Serialize\Expose
*/
protected $tin;
/**
* @var \Bidcoz\Bundle\CoreBundle\Entity\PaymentPlan
* @ORM\ManyToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\PaymentPlan")
* @ORM\JoinColumn(name="payment_model", referencedColumnName="id", nullable=false)
* @Assert\NotNull
*/
protected $paymentModel;
/**
* @var \DateTime
* @ORM\Column(name="payment_plan_expires_at", type="datetime", nullable=true)
*/
protected $paymentPlanExpiresAt;
/**
* @ORM\OneToMany(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\Account\OrganizationAccount", mappedBy="organization")
* @Assert\Valid
*/
protected $paymentGatewayAccounts;
/**
* @ORM\OneToMany(targetEntity="OrganizationAdmin", mappedBy="organization")
*/
protected $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="trial_countdown_date", type="datetime")
* @Serialize\Expose
*/
protected $trialCountdownDate;
/**
* @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
*/
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(type="string", length=128, nullable=true, name="directory_city")
* @Assert\NotBlank(groups={"Directory"})
* @Assert\Length(max=128, groups={"Directory"})
*/
protected $directoryCity;
public static $directoryCities = [
'Nashville' => 'Nashville',
//'Knoxville' => 'Knoxville',
//'Memphis' => 'Memphis',
//'Chattanooga' => 'Chattanooga',
];
/**
* @ORM\Column(type="string", length=2, nullable=true, name="directory_state")
* @Assert\NotBlank(groups={"Directory"})
*/
protected $directoryState;
public static $directoryStates = [
'Tennessee' => 'TN',
];
public static $directoryCityStates = [
'Nashville TN' => 'TN-Nashville',
'New York NY' => 'NY-New York',
];
/**
* @ORM\Column(type="string", length=50, nullable=true, name="directory_category")
* @Assert\NotBlank(groups={"Directory"})
*/
protected $directoryCategory;
public static $directoryCategories = [
'Arts, Culture and Humanities' => 'arts',
'Education and Research' => 'education',
'Environment and Animals' => 'environment',
'Health' => 'health',
'Human Services' => 'human-services',
'International' => 'international',
'Public, Societal Benefit' => 'society',
'Religion' => 'religion',
'Unknown' => 'unknown',
];
/**
* @ORM\Column(type="string", length=300, nullable=true, name="directory_description")
* @Assert\NotBlank(groups={"Directory"})
*/
protected $directoryDescription;
/**
* @ORM\Column(type="string", length=100, nullable=true, name="directory_url")
* @Assert\NotBlank(groups={"Directory"})
*/
protected $directoryUrl;
/**
* @ORM\Column(type="boolean", nullable=false, name="directory_enabled", options={"default" = true})
* @Assert\NotBlank(groups={"Directory"})
*/
protected $directoryEnabled = false;
/**
* @ORM\Column(name="notes", type="text", nullable=true);
*/
protected $notes;
/**
* @ORM\Column(name="allowed_contacts", type="integer")
*/
protected $allowedContacts = 5000;
/**
* @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\ManyToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\Pricing")
* @ORM\JoinColumn(name="pricing", referencedColumnName="id", nullable=false)
* @Assert\NotNull
*/
protected $pricing;
/**
* @ORM\Column(type="string", length=100, nullable=true, name="web_address")
*/
protected $webAddress;
/**
* @ORM\ManyToOne(targetEntity="Bidcoz\Bundle\CoreBundle\Entity\TaxCertificate", cascade={"remove"})
* @ORM\JoinColumn(name="tax_certificate_id", referencedColumnName="id")
* @Serialize\Expose
*/
protected $taxCertificate;
public function __construct()
{
$this->campaigns = new ArrayCollection();
$this->paymentGatewayAccounts = new ArrayCollection();
$this->admins = new ArrayCollection();
$this->theme = new Theme();
// Set trial countdown to now since we don't really want a trial.
// $this->trialCountdownDate = new \DateTime('+7 days');
$this->trialCountdownDate = new \DateTime();
$this->urlEditableUntil = new \DateTime('+7 days');
$this->createdAt = new \DateTime();
$this->paymentPlanExpiresAt = new \DateTime('+1 year');
}
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($name)
{
$this->name = $name;
}
public function getName()
{
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 getCampaigns($activeOnly = false, $returnLocked = true)
{
if ($activeOnly) {
return $this->campaigns->filter(function (Campaign $campaign) use ($returnLocked) {
if (!$returnLocked && $campaign->isLocked()) {
return false;
}
return $campaign->isActive();
});
} else {
return $this->campaigns;
}
}
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)
{
foreach ($this->getCampaigns() as $campaign) {
if ($campaign->getSlug() === $slug) {
return $campaign;
}
}
}
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 setDirectoryOnly($directoryOnly)
{
$this->directoryOnly = $directoryOnly;
}
public function isDirectoryOnly()
{
return $this->directoryOnly;
}
public function setTin($tin)
{
$this->tin = $tin;
}
public function getTin()
{
return $this->tin;
}
public function setPaymentModel($paymentModel)
{
$this->paymentModel = $paymentModel;
}
public function getPaymentModel()
{
return $this->paymentModel;
}
public function setPaymentPlanExpiresAt($paymentPlanExpiresAt)
{
$this->paymentPlanExpiresAt = $paymentPlanExpiresAt;
}
public function getPaymentPlanExpiresAt()
{
return $this->paymentPlanExpiresAt;
}
public function getDaysTillExpiration()
{
if (!$this->paymentPlanExpiresAt) {
return;
}
$now = new \DateTime();
$diff = $now->diff($this->paymentPlanExpiresAt);
if ($diff->invert) {
return 0;
}
return $diff->days;
}
public function getDaysTillTrialExpiration()
{
if (!$this->trialCountdownDate) {
return;
}
$now = new \DateTime();
$diff = $now->diff($this->trialCountdownDate);
if ($diff->invert) {
return 0;
}
return $diff->days;
}
public function isPaymentPlanExpiring(): bool
{
return null !== $this->paymentPlanExpiresAt;
}
public function isPaymentPlanExpired(): bool
{
$now = new \DateTime();
return null == $this->paymentPlanExpiresAt || ($this->isPaymentPlanExpiring() && $now > $this->getPaymentPlanExpiresAt());
}
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 getPaymentModelName()
{
return $this->paymentModel->getName();
}
public function getPaymentGatewayChoices()
{
return [
// 'PayPal' => PaymentGateway::PAYPAL,
'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 setTrialCountdownDate(\DateTime $trialCountdownDate)
{
$this->trialCountdownDate = $trialCountdownDate;
}
public function getTrialCountdownDate()
{
return $this->trialCountdownDate;
}
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 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 setAllowedContacts(int $allowedContacts)
{
$this->allowedContacts = $allowedContacts;
}
public function getAllowedContacts(): int
{
return $this->allowedContacts ?: 1000;
}
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->isEnterprise();
}
public function getKindfulToken()
{
return $this->kindfulToken;
}
public function setKindfulToken($token)
{
$this->kindfulToken = $token;
}
public function setPricing(Pricing $pricing)
{
$this->pricing = $pricing;
}
public function getPricing(): Pricing
{
return $this->pricing;
}
public function getAdmins(): ArrayCollection
{
return $this->admins;
}
public function setAdmins(ArrayCollection $admins): Organization
{
$this->admins = $admins;
return $this;
}
/**
* @return mixed
*/
public function getDirectoryCity()
{
return $this->directoryCity;
}
/**
* @param mixed $directoryCity
*
* @return Organization
*/
public function setDirectoryCity($directoryCity)
{
$this->directoryCity = $directoryCity;
return $this;
}
/**
* @return mixed
*/
public function getDirectoryState()
{
return $this->directoryState;
}
/**
* @param mixed $directoryState
*
* @return Organization
*/
public function setDirectoryState($directoryState)
{
$this->directoryState = $directoryState;
return $this;
}
/**
* @return mixed
*/
public function getDirectoryCategory()
{
return $this->directoryCategory;
}
/**
* @param mixed $directoryCategory
*
* @return Organization
*/
public function setDirectoryCategory($directoryCategory)
{
$this->directoryCategory = $directoryCategory;
return $this;
}
/**
* @return mixed
*/
public function getDirectoryDescription()
{
return $this->directoryDescription;
}
/**
* @param mixed $directoryDescription
*
* @return Organization
*/
public function setDirectoryDescription($directoryDescription)
{
$this->directoryDescription = $directoryDescription;
return $this;
}
/**
* @return mixed
*/
public function getDirectoryUrl()
{
return $this->directoryUrl;
}
/**
* @param mixed $directoryUrl
*
* @return Organization
*/
public function setDirectoryUrl($directoryUrl)
{
$this->directoryUrl = $directoryUrl;
return $this;
}
public function isDirectoryEnabled(): bool
{
return $this->directoryEnabled;
}
public function setDirectoryEnabled(bool $directoryEnabled): Organization
{
$this->directoryEnabled = $directoryEnabled;
return $this;
}
public function setTwilioAccount(TwilioAccount $twilioAccount)
{
$this->twilioAccount = $twilioAccount;
}
public function getTwilioAccount(): TwilioAccount
{
return $this->twilioAccount;
}
public function isEnterprise(): bool
{
return $this->enterprise;
}
public function setEnterprise(bool $enterprise)
{
$this->enterprise = $enterprise;
}
public function getWebAddress()
{
return $this->webAddress;
}
public function setWebAddress(string $webAddress)
{
$this->webAddress = $webAddress;
}
public function getTaxCertificate()
{
return $this->taxCertificate;
}
public function setTaxCertificate($certificate)
{
$this->taxCertificate = $certificate;
}
public function jsonSerialize()
{
return [
'name' => $this->getName(),
'logo' => $this->getLogo(),
'directoryCity' => $this->getDirectoryCity(),
'directoryState' => $this->getDirectoryState(),
'directoryCategory' => $this->getDirectoryCategory(),
'directoryDescription' => $this->getDirectoryDescription(),
'directoryUrl' => $this->getDirectoryUrl(),
'directoryEnabled' => $this->isDirectoryEnabled(),
];
}
}