models.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. from datetime import *
  2. from dateutil import relativedelta
  3. from django.db import models
  4. from django.db.models import permalink
  5. from django.utils.translation import ugettext_lazy as _
  6. from django.core.urlresolvers import reverse
  7. from django.contrib.auth.models import User
  8. from django.contrib.localflavor.us.models import PhoneNumberField, USStateField
  9. from directory.models import Point, Person, Town, Place
  10. class StandardMetadata(models.Model):
  11. """
  12. A basic (abstract) model for metadata.
  13. Included in each model file to maintain application separation.
  14. Subclass new models from 'StandardMetadata' instead of 'models.Model'.
  15. """
  16. created = models.DateTimeField(default=datetime.now, editable=False)
  17. updated = models.DateTimeField(default=datetime.now, editable=False)
  18. class Meta:
  19. abstract = True
  20. def save(self, *args, **kwargs):
  21. self.updated = datetime.now()
  22. super(StandardMetadata, self).save(*args, **kwargs)
  23. class Category(models.Model):
  24. """Place categories model."""
  25. title = models.CharField(_("title"), max_length=100, unique=True)
  26. slug = models.SlugField(_("slug"), unique=True)
  27. class Meta:
  28. verbose_name = _("category")
  29. verbose_name_plural = _("categories")
  30. ordering = ("title",)
  31. def __unicode__(self):
  32. return u"%s" % self.title
  33. def get_absolute_url(self):
  34. return reverse("mk-category-index", args=[self.slug])
  35. class Subcategory(models.Model):
  36. """Place subcategories model."""
  37. title = models.CharField(_("title"), max_length=100, unique=True)
  38. slug = models.SlugField(_("slug"), unique=True)
  39. category = models.ForeignKey(Category)
  40. class Meta:
  41. verbose_name = _("subcategory")
  42. verbose_name_plural = _("subcategories")
  43. ordering = (
  44. "category",
  45. "title",
  46. )
  47. def __unicode__(self):
  48. return u"%s" % self.title
  49. def get_absolute_url(self):
  50. args = [self.category.slug, self.slug]
  51. return reverse("mk-subcategory-index", args=args)
  52. class Feature(models.Model):
  53. name = models.CharField(_("name"), max_length=200)
  54. slug = models.SlugField(_("slug"), unique=True)
  55. description = models.CharField(
  56. _("description"), max_length=255, blank=True, null=True
  57. )
  58. class Meta:
  59. verbose_name = _("feature")
  60. verbose_name_plural = _("features")
  61. ordering = ("name",)
  62. def __unicode__(self):
  63. return u"%s" % self.name
  64. class PaymentMethod(StandardMetadata):
  65. """Payment methods accepted by businesses."""
  66. name = models.CharField(_("name"), max_length=50)
  67. slug = models.SlugField(_("slug"), unique=True)
  68. icon = models.ImageField(
  69. _("icon"), upload_to="marketplace/paymenticons/", blank=True, null=True
  70. )
  71. class Meta:
  72. verbose_name = _("payment method")
  73. verbose_name_plural = _("payment methods")
  74. ordering = ("name",)
  75. def __unicode__(self):
  76. return u"%s" % self.name
  77. # def get_absolute_url(self):
  78. # args=[self.slug]
  79. # return reverse ('mk-payment-method-detail', args=args)
  80. class Business(StandardMetadata):
  81. """Base class for business models for Marketplace application.
  82. A business at it's simplest is a listing.
  83. It can be piled up with all manner of other things as upsells.
  84. Upsells are represented by the objects listing status."""
  85. STATUS_CHOICES = (
  86. (0, "Inactive"),
  87. (1, "Basic"),
  88. (2, "Full"),
  89. (3, "Hosted"),
  90. )
  91. point = models.ForeignKey(Point, blank=True, null=True)
  92. owner = models.ForeignKey(
  93. Person, blank=True, null=True
  94. ) # Eventually we want this to be a UserProfile class
  95. name = models.CharField(_("name"), max_length=255)
  96. slug = models.SlugField(_("slug"), unique=True)
  97. brief_hours = models.CharField(
  98. _("brief hours"), blank=True, null=True, max_length=255
  99. )
  100. logo = models.ImageField(
  101. _("logo or photo"), upload_to="marketplace/logos/", blank=True
  102. )
  103. unit = models.CharField(
  104. _("unit"), blank=True, max_length=100, help_text="Suite or Apartment #"
  105. )
  106. po_box = models.CharField(_("post office box"), blank=True, null=True, max_length=5)
  107. post_office = models.ForeignKey(
  108. Place, related_name="post_office", blank=True, null=True
  109. )
  110. phone = PhoneNumberField(_("primary phone"), blank=True, null=True)
  111. phone_title = models.CharField(
  112. _("phone one title"), blank=True, null=True, max_length=25
  113. )
  114. phone_2 = PhoneNumberField(_("phone two"), blank=True, null=True)
  115. phone_2_title = models.CharField(
  116. _("phone two title"), blank=True, null=True, max_length=25
  117. )
  118. phone_3 = PhoneNumberField(_("phone three"), blank=True, null=True)
  119. phone_3_title = models.CharField(
  120. _("phone three title"), blank=True, null=True, max_length=25
  121. )
  122. mobile_phone = PhoneNumberField(_("mobile phone"), blank=True, null=True)
  123. fax = PhoneNumberField(_("fax"), blank=True, null=True)
  124. url = models.URLField(_("url"), blank=True, verify_exists=False)
  125. email = models.EmailField(_("email"), blank=True)
  126. brief_hours = models.CharField(
  127. _("brief hours"), blank=True, null=True, max_length=255
  128. )
  129. directions = models.CharField(
  130. _("directions"), blank=True, null=True, max_length=255
  131. )
  132. twitter = models.CharField(
  133. _("twitter account"), blank=True, null=True, max_length=255
  134. )
  135. facebook = models.CharField(
  136. _("facebook profile"), blank=True, null=True, max_length=255
  137. )
  138. brief = models.CharField(_("brief"), max_length=140, blank=True, null=True)
  139. description = models.TextField(_("description"), blank=True, null=True)
  140. payment_accepted = models.ManyToManyField(PaymentMethod, blank=True, null=True)
  141. status = models.IntegerField(_("listing status"), choices=STATUS_CHOICES, default=1)
  142. paid_through = models.DateField(_("paid through date"), blank=True, null=True)
  143. features = models.ManyToManyField(Feature, blank=True, null=True)
  144. categories = models.ManyToManyField(Category)
  145. subcategories = models.ManyToManyField(Subcategory)
  146. with_branches = models.BooleanField(
  147. _("show with branches"),
  148. default=True,
  149. help_text="If this business has branch offices, do we show this listing as the primary office?",
  150. )
  151. internal_notes = models.TextField(
  152. _("Internal notes"),
  153. blank=True,
  154. null=True,
  155. help_text="Does not appear on public site, only for admin notes.",
  156. )
  157. class Meta:
  158. verbose_name = _("business")
  159. verbose_name_plural = _("businesses")
  160. ordering = ("point__town", "name")
  161. get_latest_by = "created"
  162. def __unicode__(self):
  163. return u"%s" % self.name
  164. def get_absolute_url(self):
  165. return reverse("mk-business-detail", args=[self.slug])
  166. class BusinessPhoto(StandardMetadata):
  167. business = models.ForeignKey(Business)
  168. branch = models.ForeignKey("Branch", blank=True, null=True)
  169. photo = models.ImageField(
  170. _("photo"), upload_to="marketplace/photos/", blank=True, null=True
  171. )
  172. caption = models.CharField(_("caption"), max_length=255, blank=True, null=True)
  173. credit = models.CharField(_("credit"), blank=True, null=True, max_length=150)
  174. ordering = models.IntegerField(_("ordering"), max_length=3, blank=True, null=True)
  175. class Meta:
  176. ordering = ["ordering"]
  177. get_latest_by = "created"
  178. verbose_name = _("business photo")
  179. verbose_name_plural = _("business photos")
  180. def __unicode__(self):
  181. return self.business.name + " photo"
  182. def __str__(self):
  183. return self.__unicode__()
  184. class Branch(StandardMetadata):
  185. """Branch model
  186. A branch is another physical location of a business. For example, banks often have multiple
  187. branches. Branches do not exist without an associated business, but most contact information
  188. can be unique from the business.
  189. It is assumed at this point that all branches share the same features and payment methods as
  190. their central office. Though in the long run, this may not be a desirable way to manage these things.
  191. """
  192. business = models.ForeignKey(Business)
  193. name = models.CharField(_("name"), blank=True, null=True, max_length=150)
  194. point = models.ForeignKey(Point, blank=True, null=True)
  195. slug = models.SlugField(_("slug"), unique=True)
  196. logo = models.ImageField(
  197. _("logo or photo"), upload_to="marketplace/logos/", blank=True
  198. )
  199. unit = models.CharField(
  200. _("unit"), blank=True, max_length=100, help_text="Suite or Apartment #"
  201. )
  202. po_box = models.CharField(_("post office box"), blank=True, null=True, max_length=5)
  203. brief_hours = models.CharField(
  204. _("brief hours"), blank=True, null=True, max_length=255
  205. )
  206. phone = PhoneNumberField(_("primary phone"), blank=True, null=True)
  207. tollfree_phone = PhoneNumberField(_("toll-free phone"), blank=True, null=True)
  208. mobile_phone = PhoneNumberField(_("mobile phone"), blank=True, null=True)
  209. fax = PhoneNumberField(_("fax"), blank=True, null=True)
  210. url = models.URLField(_("url"), blank=True, verify_exists=False)
  211. email = models.EmailField(_("email"), blank=True)
  212. twitter = models.CharField(
  213. _("twitter account"), blank=True, null=True, max_length=255
  214. )
  215. facebook = models.CharField(
  216. _("facebook profile"), blank=True, null=True, max_length=255
  217. )
  218. class Meta:
  219. verbose_name = _("branch office")
  220. verbose_name_plural = _("branch offices")
  221. ordering = ("business", "point")
  222. get_latest_by = "created"
  223. def __unicode__(self):
  224. return u"%s, %s branch" % (self.business, self.point.town.name)
  225. def get_absolute_url(self):
  226. return reverse("mk-branch-detail", args=[self.slug])
  227. class BaseHours(models.Model):
  228. mon_open = models.TimeField(_("monday opening"), blank=True, null=True)
  229. mon_close = models.TimeField(_("monday closing"), blank=True, null=True)
  230. tue_open = models.TimeField(_("tuesday opening"), blank=True, null=True)
  231. tue_close = models.TimeField(_("tuesday closing"), blank=True, null=True)
  232. wed_open = models.TimeField(_("wednesday opening"), blank=True, null=True)
  233. wed_close = models.TimeField(_("wednesday closing"), blank=True, null=True)
  234. thu_open = models.TimeField(_("thursday opening"), blank=True, null=True)
  235. thu_close = models.TimeField(_("thursday closing"), blank=True, null=True)
  236. fri_open = models.TimeField(_("friday opening"), blank=True, null=True)
  237. fri_close = models.TimeField(_("friday closing"), blank=True, null=True)
  238. sat_open = models.TimeField(_("saturday opening"), blank=True, null=True)
  239. sat_close = models.TimeField(_("saturday closing"), blank=True, null=True)
  240. sun_open = models.TimeField(_("sunday opening"), blank=True, null=True)
  241. sun_close = models.TimeField(_("sunday closing"), blank=True, null=True)
  242. class Meta:
  243. abstract = True
  244. class Hours(BaseHours):
  245. title = models.CharField(_("title"), blank=True, null=True, max_length=100)
  246. business = models.ForeignKey(Business)
  247. branch = models.ForeignKey(Branch, blank=True, null=True)
  248. mon_by_appt = models.BooleanField(_("monday by appt"), default=False)
  249. tue_by_appt = models.BooleanField(_("tuesday by appt"), default=False)
  250. wed_by_appt = models.BooleanField(_("wednesday by appt"), default=False)
  251. thu_by_appt = models.BooleanField(_("thursday by appt"), default=False)
  252. fri_by_appt = models.BooleanField(_("friday by appt"), default=False)
  253. sat_by_appt = models.BooleanField(_("saturday by appt"), default=False)
  254. sun_by_appt = models.BooleanField(_("sunday by appt"), default=False)
  255. addtional = models.CharField(
  256. _("additional info"), blank=True, null=True, max_length=200
  257. )
  258. class Meta:
  259. verbose_name = _("hours")
  260. verbose_name_plural = _("hours")
  261. def __unicode__(self):
  262. return u"%s hours" % (self.business)
  263. class Meal(models.Model):
  264. name = models.CharField(_("name"), max_length=100)
  265. slug = models.SlugField(_("slug"), unique=True)
  266. def __unicode__(self):
  267. return self.name
  268. class Menu(StandardMetadata):
  269. business = models.ForeignKey(Business)
  270. file = models.FileField(
  271. _("file"), upload_to="marketplace/menus/", blank=True, null=True
  272. )
  273. menu_text = models.TextField(_("menu text"), blank=True, null=True)
  274. expire_date = models.DateField(_("valid until"), blank=True, null=True)
  275. meal = models.ForeignKey(Meal)
  276. sample = models.BooleanField(
  277. _("sample"),
  278. default=False,
  279. help_text="Use this if your menu is to be used only as a sample of the sorts of food served.",
  280. )
  281. def __unicode__(self):
  282. return u"%s %s menu" % (self.business, self.meal)
  283. class DiningHours(BaseHours):
  284. business = models.ForeignKey(Business)
  285. branch = models.ForeignKey(Branch, blank=True, null=True)
  286. meal = models.ForeignKey(Meal)
  287. additional = models.CharField(
  288. _("additional info"), blank=True, null=True, max_length=200
  289. )
  290. class Meta:
  291. verbose_name = _("dining hours")
  292. verbose_name_plural = _("dining hours")
  293. def __unicode__(self):
  294. return u"%s - %s hours" % (self.business, self.meal)
  295. class Link(StandardMetadata):
  296. business = models.ForeignKey(Business)
  297. url = models.URLField("URL", verify_exists=False)
  298. title = models.CharField(_("title"), max_length=255)
  299. description = models.CharField(
  300. _("description"), max_length=200, blank=True, null=True
  301. )
  302. class Meta:
  303. verbose_name = _("link")
  304. verbose_name_plural = _("links")
  305. ordering = ("created", "updated")
  306. get_latest_by = "created"
  307. def __unicode__(self):
  308. return self.title
  309. class Reference(StandardMetadata):
  310. business = models.ForeignKey(Business)
  311. source = models.CharField(_("source"), max_length=255)
  312. slug = models.SlugField(_("slug"))
  313. body = models.CharField(_("description"), max_length=255)
  314. class Meta:
  315. verbose_name = _("reference")
  316. verbose_name_plural = _("references")
  317. ordering = ("created", "updated")
  318. get_latest_by = "created"
  319. def __unicode__(self):
  320. return u"%s reference from %s" % (self.business, self.source)
  321. class Ad(StandardMetadata):
  322. business = models.ForeignKey(Business)
  323. title = models.CharField(_("title"), max_length=255)
  324. slug = models.SlugField(_("slug"))
  325. start_date = models.DateField(_("start date"), blank=True, null=True)
  326. expire_date = models.DateField(_("expiration date"), blank=True, null=True)
  327. body = models.CharField(_("description"), max_length=200, blank=True, null=True)
  328. file = models.FileField(_("file"), upload_to="marketplace/flyers/")
  329. class Meta:
  330. verbose_name = _("advert")
  331. verbose_name_plural = _("adverts")
  332. ordering = ("created", "updated")
  333. get_latest_by = "created"
  334. def __unicode__(self):
  335. return u"%s ad - %s" % (self.business, self.title)
  336. def get_absolute_url(self):
  337. args = [self.business.slug, self.slug]
  338. return reverse("mk-ad-detail", args=args)
  339. class Guide(StandardMetadata):
  340. title = models.CharField(_("title"), max_length=255)
  341. slug = models.SlugField(_("slug"))
  342. published = models.BooleanField(_("published"), default=False)
  343. pub_date = models.DateField(_("publish date"))
  344. featured = models.BooleanField(_("featured"), default=False)
  345. logo = models.ImageField(
  346. _("logo or photo"), upload_to="marketplace/guides/logos/", blank=True
  347. )
  348. logo_thumbnail = models.ImageField(
  349. _("Thumbnail of logo (optionl)"),
  350. upload_to="marketplace/section/logos/thumbnails/",
  351. blank=True,
  352. null=True,
  353. help_text="An optional thumbnail of the logo. If not used, a thumbnail will be generated from the logo.",
  354. )
  355. tag_line = models.CharField(_("Tag line"), max_length=255, blank=True, null=True)
  356. brief_description = models.CharField(
  357. _("Brief description"), max_length=255, blank=True, null=True
  358. )
  359. description = models.TextField(_("description"), blank=True, null=True)
  360. categories = models.ManyToManyField(Category, blank=True, null=True)
  361. subcategories = models.ManyToManyField(Subcategory, blank=True, null=True)
  362. businesses = models.ManyToManyField(Business, blank=True, null=True)
  363. template_name = models.CharField(
  364. _("template name"),
  365. max_length=70,
  366. blank=True,
  367. help_text=_(
  368. "Example: 'marketplace/guides/seasonal_guide.html'. If this isn't provided, the system will use 'marketplace/guides/default.html'."
  369. ),
  370. )
  371. class Meta:
  372. verbose_name = _("Guide")
  373. verbose_name_plural = _("Guides")
  374. ordering = ("pub_date", "updated")
  375. get_latest_by = "pub_date"
  376. def __unicode__(self):
  377. return u"%s" % (self.title)
  378. def get_absolute_url(self):
  379. args = [self.slug]
  380. return reverse("mk-guide-detail", args=args)