diff --git a/rattail/django/rattail/admin.py b/rattail/django/rattail/admin.py
index 51a345e..621db96 100644
--- a/rattail/django/rattail/admin.py
+++ b/rattail/django/rattail/admin.py
@@ -27,8 +27,10 @@
"""
from django.contrib import admin
+from django.contrib.admin.widgets import AdminTextInputWidget
from rattail.django.rattail.models import *
+from rattail.django.rattail.models.rattail import GPCField
class ModelAdmin(admin.ModelAdmin):
@@ -36,27 +38,74 @@ class ModelAdmin(admin.ModelAdmin):
Base admin manager for all Rattail models.
"""
- def get_form(self, request, obj=None, **kwargs):
- kwargs.setdefault('exclude', ('uuid',))
- form = super(ModelAdmin, self).get_form(request, obj, **kwargs)
- return form
+ exclude = ('uuid',)
-class StoreContactInfoInline(admin.TabularInline):
+class ContactInfoInline(admin.TabularInline):
+ """
+ Base inline manager for all contact info models.
+ """
+
exclude = ('uuid', 'parent_type')
extra = 0
-class StorePhoneNumberInline(StoreContactInfoInline):
- model = StorePhoneNumber
- verbose_name_plural = "Phone Numbers"
-class StoreEmailAddressInline(StoreContactInfoInline):
+class PersonPhoneNumberInline(ContactInfoInline):
+ model = PersonPhoneNumber
+
+class PersonEmailAddressInline(ContactInfoInline):
+ model = PersonEmailAddress
+
+class PersonAdmin(ModelAdmin):
+ inlines = [PersonPhoneNumberInline, PersonEmailAddressInline]
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ContactInfoInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
+admin.site.register(Person, PersonAdmin)
+
+
+admin.site.register(Role, ModelAdmin)
+
+
+class UserRoleInline(admin.TabularInline):
+ model = UserRole
+ verbose_name = "Role"
+ verbose_name_plural = "Roles"
+ exclude = ('uuid',)
+ extra = 0
+
+class UserAdmin(ModelAdmin):
+ exclude = ('uuid', 'password', 'salt')
+ inlines = [UserRoleInline]
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, UserRoleInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
+admin.site.register(User, UserAdmin)
+
+
+class StorePhoneNumberInline(ContactInfoInline):
+ model = StorePhoneNumber
+
+class StoreEmailAddressInline(ContactInfoInline):
model = StoreEmailAddress
- verbose_name_plural = "Email Addresses"
class StoreAdmin(ModelAdmin):
inlines = [StorePhoneNumberInline, StoreEmailAddressInline]
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ContactInfoInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
admin.site.register(Store, StoreAdmin)
@@ -72,13 +121,120 @@ admin.site.register(Category, ModelAdmin)
admin.site.register(Brand, ModelAdmin)
+class VendorPhoneNumberInline(ContactInfoInline):
+ model = VendorPhoneNumber
+
+class VendorEmailAddressInline(ContactInfoInline):
+ model = VendorEmailAddress
+
+class VendorContactInline(admin.TabularInline):
+ model = VendorContact
+ verbose_name = "Contact"
+ verbose_name_plural = "Contacts"
+ exclude = ('uuid',)
+ extra = 0
+
+class VendorAdmin(ModelAdmin):
+ inlines = [VendorPhoneNumberInline, VendorEmailAddressInline,
+ VendorContactInline]
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ContactInfoInline) and obj is None:
+ continue
+ if isinstance(inline, VendorContactInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
+admin.site.register(Vendor, VendorAdmin)
+
+
class ProductPriceInline(admin.TabularInline):
model = ProductPrice
+ verbose_name = "Price"
verbose_name_plural = "Prices"
exclude = ('uuid',)
extra = 0
+class ProductCostInline(admin.TabularInline):
+ model = ProductCost
+ verbose_name = "Cost"
+ verbose_name_plural = "Costs"
+ exclude = ('uuid',)
+ extra = 0
+
class ProductAdmin(ModelAdmin):
- inlines = [ProductPriceInline]
+ inlines = [ProductPriceInline, ProductCostInline]
+
+ formfield_overrides = {
+ GPCField: {
+ 'widget': AdminTextInputWidget,
+ },
+ }
+
+ def get_form(self, request, obj=None, **kwargs):
+ if obj is None:
+ kwargs['exclude'] = ('uuid', 'regular_price', 'current_price')
+ return super(ProductAdmin, self).get_form(request, obj, **kwargs)
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ProductPriceInline) and obj is None:
+ continue
+ if isinstance(inline, ProductCostInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
admin.site.register(Product, ProductAdmin)
+
+
+class EmployeePhoneNumberInline(ContactInfoInline):
+ model = EmployeePhoneNumber
+
+class EmployeeEmailAddressInline(ContactInfoInline):
+ model = EmployeeEmailAddress
+
+class EmployeeAdmin(ModelAdmin):
+ inlines = [EmployeePhoneNumberInline, EmployeeEmailAddressInline]
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ContactInfoInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
+admin.site.register(Employee, EmployeeAdmin)
+
+
+admin.site.register(CustomerGroup, ModelAdmin)
+
+
+class CustomerPhoneNumberInline(ContactInfoInline):
+ model = CustomerPhoneNumber
+
+class CustomerEmailAddressInline(ContactInfoInline):
+ model = CustomerEmailAddress
+
+class CustomerGroupAssignmentInline(admin.TabularInline):
+ model = CustomerGroupAssignment
+ verbose_name = "Group Assignment"
+ verbose_name_plural = "Group Assignments"
+ exclude = ('uuid',)
+ extra = 0
+
+class CustomerAdmin(ModelAdmin):
+ inlines = [CustomerPhoneNumberInline, CustomerEmailAddressInline,
+ CustomerGroupAssignmentInline]
+
+ def get_formsets(self, request, obj=None):
+ for inline in self.get_inline_instances(request):
+ if isinstance(inline, ContactInfoInline) and obj is None:
+ continue
+ if isinstance(inline, CustomerGroupAssignmentInline) and obj is None:
+ continue
+ yield inline.get_formset(request, obj)
+
+admin.site.register(Customer, CustomerAdmin)
+
+
+admin.site.register(LabelProfile, ModelAdmin)
diff --git a/rattail/django/rattail/migrations/0001_initial.py b/rattail/django/rattail/migrations/0001_initial.py
index e1586a6..f04bdd0 100644
--- a/rattail/django/rattail/migrations/0001_initial.py
+++ b/rattail/django/rattail/migrations/0001_initial.py
@@ -8,6 +8,15 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
+ # Adding model 'Person'
+ db.create_table('rattail_people', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('first_name', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True)),
+ ('last_name', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True)),
+ ('display_name', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['Person'])
+
# Adding model 'PhoneNumber'
db.create_table('rattail_phone_numbers', (
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
@@ -30,6 +39,31 @@ class Migration(SchemaMigration):
))
db.send_create_signal('rattail', ['EmailAddress'])
+ # Adding model 'Role'
+ db.create_table('rattail_roles', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=25)),
+ ))
+ db.send_create_signal('rattail', ['Role'])
+
+ # Adding model 'User'
+ db.create_table('rattail_users', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('username', self.gf('django.db.models.fields.CharField')(unique=True, max_length=25)),
+ ('password', self.gf('django.db.models.fields.CharField')(max_length=60, null=True, blank=True)),
+ ('salt', self.gf('django.db.models.fields.CharField')(max_length=29, null=True, blank=True)),
+ ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], null=True, db_column='person_uuid', blank=True)),
+ ))
+ db.send_create_signal('rattail', ['User'])
+
+ # Adding model 'UserRole'
+ db.create_table('rattail_users_roles', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.User'], db_column='user_uuid')),
+ ('role', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Role'], db_column='role_uuid')),
+ ))
+ db.send_create_signal('rattail', ['UserRole'])
+
# Adding model 'Store'
db.create_table('rattail_stores', (
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
@@ -71,6 +105,24 @@ class Migration(SchemaMigration):
))
db.send_create_signal('rattail', ['Brand'])
+ # Adding model 'Vendor'
+ db.create_table('rattail_vendors', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('id', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
+ ('special_discount', self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=5, decimal_places=3, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['Vendor'])
+
+ # Adding model 'VendorContact'
+ db.create_table('rattail_vendor_contacts', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('vendor', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Vendor'], db_column='vendor_uuid')),
+ ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], db_column='person_uuid')),
+ ('preference', self.gf('django.db.models.fields.IntegerField')()),
+ ))
+ db.send_create_signal('rattail', ['VendorContact'])
+
# Adding model 'Product'
db.create_table('rattail_products', (
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
@@ -83,6 +135,8 @@ class Migration(SchemaMigration):
('description2', self.gf('django.db.models.fields.CharField')(max_length=60, null=True, blank=True)),
('size', self.gf('django.db.models.fields.CharField')(max_length=30, null=True, blank=True)),
('unit_of_measure', self.gf('django.db.models.fields.CharField')(max_length=4, null=True, blank=True)),
+ ('regular_price', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, db_column='regular_price_uuid', to=orm['rattail.ProductPrice'])),
+ ('current_price', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, db_column='current_price_uuid', to=orm['rattail.ProductPrice'])),
))
db.send_create_signal('rattail', ['Product'])
@@ -101,14 +155,115 @@ class Migration(SchemaMigration):
))
db.send_create_signal('rattail', ['ProductPrice'])
+ # Adding model 'ProductCost'
+ db.create_table('rattail_product_costs', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('product', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Product'], db_column='product_uuid')),
+ ('vendor', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Vendor'], db_column='vendor_uuid')),
+ ('preference', self.gf('django.db.models.fields.IntegerField')()),
+ ('code', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
+ ('case_size', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('case_cost', self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=9, decimal_places=5, blank=True)),
+ ('pack_size', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('pack_cost', self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=9, decimal_places=5, blank=True)),
+ ('unit_cost', self.gf('django.db.models.fields.DecimalField')(null=True, max_digits=9, decimal_places=5, blank=True)),
+ ('effective', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['ProductCost'])
+
+ # Adding model 'Employee'
+ db.create_table('rattail_employees', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('id', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], db_column='person_uuid')),
+ ('status', self.gf('django.db.models.fields.IntegerField')()),
+ ('display_name', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['Employee'])
+
+ # Adding model 'Customer'
+ db.create_table('rattail_customers', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('id', self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+ ('email_preference', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['Customer'])
+
+ # Adding model 'CustomerPerson'
+ db.create_table('rattail_customers_people', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('customer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Customer'], db_column='customer_uuid')),
+ ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], db_column='person_uuid')),
+ ('ordinal', self.gf('django.db.models.fields.IntegerField')()),
+ ))
+ db.send_create_signal('rattail', ['CustomerPerson'])
+
+ # Adding model 'CustomerGroup'
+ db.create_table('rattail_customer_groups', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('id', self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+ ))
+ db.send_create_signal('rattail', ['CustomerGroup'])
+
+ # Adding model 'CustomerGroupAssignment'
+ db.create_table('rattail_customers_groups', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('customer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Customer'], db_column='customer_uuid')),
+ ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.CustomerGroup'], db_column='group_uuid')),
+ ('ordinal', self.gf('django.db.models.fields.IntegerField')()),
+ ))
+ db.send_create_signal('rattail', ['CustomerGroupAssignment'])
+
+ # Adding model 'LabelProfile'
+ db.create_table('rattail_label_profiles', (
+ ('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
+ ('ordinal', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('code', self.gf('django.db.models.fields.CharField')(max_length=3, null=True, blank=True)),
+ ('description', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True)),
+ ('printer_spec', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+ ('formatter_spec', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+ ('format', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('visible', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ))
+ db.send_create_signal('rattail', ['LabelProfile'])
+
def backwards(self, orm):
+ # Deleting model 'LabelProfile'
+ db.delete_table('rattail_label_profiles')
+
+ # Deleting model 'CustomerGroupAssignment'
+ db.delete_table('rattail_customers_groups')
+
+ # Deleting model 'CustomerGroup'
+ db.delete_table('rattail_customer_groups')
+
+ # Deleting model 'CustomerPerson'
+ db.delete_table('rattail_customers_people')
+
+ # Deleting model 'Customer'
+ db.delete_table('rattail_customers')
+
+ # Deleting model 'Employee'
+ db.delete_table('rattail_employees')
+
+ # Deleting model 'ProductCost'
+ db.delete_table('rattail_product_costs')
+
# Deleting model 'ProductPrice'
db.delete_table('rattail_product_prices')
# Deleting model 'Product'
db.delete_table('rattail_products')
+ # Deleting model 'VendorContact'
+ db.delete_table('rattail_vendor_contacts')
+
+ # Deleting model 'Vendor'
+ db.delete_table('rattail_vendors')
+
# Deleting model 'Brand'
db.delete_table('rattail_brands')
@@ -124,14 +279,33 @@ class Migration(SchemaMigration):
# Deleting model 'Store'
db.delete_table('rattail_stores')
+ # Deleting model 'UserRole'
+ db.delete_table('rattail_users_roles')
+
+ # Deleting model 'User'
+ db.delete_table('rattail_users')
+
+ # Deleting model 'Role'
+ db.delete_table('rattail_roles')
+
# Deleting model 'EmailAddress'
db.delete_table('rattail_email_addresses')
# Deleting model 'PhoneNumber'
db.delete_table('rattail_phone_numbers')
+ # Deleting model 'Person'
+ db.delete_table('rattail_people')
+
models = {
+ 'rattail.person': {
+ 'Meta': {'object_name': 'Person', 'db_table': "'rattail_people'"},
+ 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
'rattail.phonenumber': {
'Meta': {'object_name': 'PhoneNumber', 'db_table': "'rattail_phone_numbers'"},
'number': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
@@ -150,6 +324,25 @@ class Migration(SchemaMigration):
'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
},
+ 'rattail.role': {
+ 'Meta': {'object_name': 'Role', 'db_table': "'rattail_roles'"},
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.user': {
+ 'Meta': {'object_name': 'User', 'db_table': "'rattail_users'"},
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '60', 'null': 'True', 'blank': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'null': 'True', 'db_column': "'person_uuid'", 'blank': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '29', 'null': 'True', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.userrole': {
+ 'Meta': {'object_name': 'UserRole', 'db_table': "'rattail_users_roles'"},
+ 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Role']", 'db_column': "'role_uuid'"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.User']", 'db_column': "'user_uuid'"}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
'rattail.store': {
'Meta': {'object_name': 'Store', 'db_table': "'rattail_stores'"},
'id': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
@@ -181,13 +374,29 @@ class Migration(SchemaMigration):
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
},
+ 'rattail.vendor': {
+ 'Meta': {'object_name': 'Vendor', 'db_table': "'rattail_vendors'"},
+ 'id': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'special_discount': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '3', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.vendorcontact': {
+ 'Meta': {'object_name': 'VendorContact', 'db_table': "'rattail_vendor_contacts'"},
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
+ 'preference': ('django.db.models.fields.IntegerField', [], {}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'}),
+ 'vendor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Vendor']", 'db_column': "'vendor_uuid'"})
+ },
'rattail.product': {
'Meta': {'object_name': 'Product', 'db_table': "'rattail_products'"},
'brand': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Brand']", 'null': 'True', 'db_column': "'brand_uuid'", 'blank': 'True'}),
'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Category']", 'null': 'True', 'db_column': "'category_uuid'", 'blank': 'True'}),
+ 'current_price': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'current_price_uuid'", 'to': "orm['rattail.ProductPrice']"}),
'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Department']", 'null': 'True', 'db_column': "'department_uuid'", 'blank': 'True'}),
'description': ('django.db.models.fields.CharField', [], {'max_length': '60', 'null': 'True', 'blank': 'True'}),
'description2': ('django.db.models.fields.CharField', [], {'max_length': '60', 'null': 'True', 'blank': 'True'}),
+ 'regular_price': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'db_column': "'regular_price_uuid'", 'to': "orm['rattail.ProductPrice']"}),
'size': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
'subdepartment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Subdepartment']", 'null': 'True', 'db_column': "'subdepartment_uuid'", 'blank': 'True'}),
'unit_of_measure': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
@@ -207,6 +416,66 @@ class Migration(SchemaMigration):
'type': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
},
+ 'rattail.productcost': {
+ 'Meta': {'object_name': 'ProductCost', 'db_table': "'rattail_product_costs'"},
+ 'case_cost': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '9', 'decimal_places': '5', 'blank': 'True'}),
+ 'case_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'effective': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'pack_cost': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '9', 'decimal_places': '5', 'blank': 'True'}),
+ 'pack_size': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'preference': ('django.db.models.fields.IntegerField', [], {}),
+ 'product': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Product']", 'db_column': "'product_uuid'"}),
+ 'unit_cost': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '9', 'decimal_places': '5', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'}),
+ 'vendor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Vendor']", 'db_column': "'vendor_uuid'"})
+ },
+ 'rattail.employee': {
+ 'Meta': {'object_name': 'Employee', 'db_table': "'rattail_employees'"},
+ 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
+ 'status': ('django.db.models.fields.IntegerField', [], {}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.customer': {
+ 'Meta': {'object_name': 'Customer', 'db_table': "'rattail_customers'"},
+ 'email_preference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.customerperson': {
+ 'Meta': {'object_name': 'CustomerPerson', 'db_table': "'rattail_customers_people'"},
+ 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Customer']", 'db_column': "'customer_uuid'"}),
+ 'ordinal': ('django.db.models.fields.IntegerField', [], {}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.customergroup': {
+ 'Meta': {'object_name': 'CustomerGroup', 'db_table': "'rattail_customer_groups'"},
+ 'id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.customergroupassignment': {
+ 'Meta': {'object_name': 'CustomerGroupAssignment', 'db_table': "'rattail_customers_groups'"},
+ 'customer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Customer']", 'db_column': "'customer_uuid'"}),
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.CustomerGroup']", 'db_column': "'group_uuid'"}),
+ 'ordinal': ('django.db.models.fields.IntegerField', [], {}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
+ },
+ 'rattail.labelprofile': {
+ 'Meta': {'object_name': 'LabelProfile', 'db_table': "'rattail_label_profiles'"},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'format': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'formatter_spec': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ordinal': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'printer_spec': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'}),
+ 'visible': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
}
complete_apps = ['rattail']
diff --git a/rattail/django/rattail/models/__init__.py b/rattail/django/rattail/models/__init__.py
index 35a8666..006467b 100644
--- a/rattail/django/rattail/models/__init__.py
+++ b/rattail/django/rattail/models/__init__.py
@@ -31,6 +31,8 @@ from __future__ import absolute_import
from south.modelsinspector import add_introspection_rules
from rattail.django.rattail.models.core import *
+from rattail.django.rattail.models.contact import *
+from rattail.django.rattail.models.auth import *
from rattail.django.rattail.models.rattail import *
diff --git a/rattail/django/rattail/models/auth.py b/rattail/django/rattail/models/auth.py
new file mode 100644
index 0000000..8ad9c79
--- /dev/null
+++ b/rattail/django/rattail/models/auth.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Rattail -- Retail Software Framework
+# Copyright © 2010-2012 Lance Edgar
+#
+# This file is part of Rattail.
+#
+# Rattail is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+# more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Rattail. If not, see .
+#
+################################################################################
+
+"""
+``rattail.django.rattail.models.auth`` -- Models for 'auth' Extension
+"""
+
+from __future__ import absolute_import
+
+from django.db import models
+
+from rattail.django.rattail.models import Model, uuid_field
+
+
+__all__ = ['Role', 'User', 'UserRole']
+
+
+class Role(Model):
+ """
+ Represents a role within the system; used to manage permissions.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('roles')
+
+ uuid = uuid_field()
+ name = models.CharField(max_length=25, unique=True)
+
+ def __repr__(self):
+ return "" % self.name
+
+ def __unicode__(self):
+ return unicode(self.name or '')
+
+
+class User(Model):
+ """
+ Represents a user of the system. This may or may not correspond to a real
+ person, i.e. some users may exist solely for automated tasks.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('users')
+
+ uuid = uuid_field()
+ username = models.CharField(max_length=25, unique=True)
+ password = models.CharField(max_length=60, blank=True, null=True)
+ salt = models.CharField(max_length=29, blank=True, null=True)
+ person = models.ForeignKey('Person', db_column='person_uuid', blank=True, null=True)
+
+ def __repr__(self):
+ return "" % self.username
+
+ def __unicode__(self):
+ return unicode(self.username or '')
+
+ @property
+ def display_name(self):
+ """
+ Returns :attr:`rattail.Person.display_name` if present; otherwise
+ returns :attr:`username`.
+ """
+
+ if self.person and self.person.display_name:
+ return self.person.display_name
+ return self.username
+
+
+class UserRole(Model):
+ """
+ Represents the association between a :class:`User` and a :class:`Role`.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('users_roles')
+
+ uuid = uuid_field()
+ user = models.ForeignKey(User, db_column='user_uuid')
+ role = models.ForeignKey(Role, db_column='role_uuid')
+
+ def __repr__(self):
+ return "" % (self.user, self.role)
+
+ def __unicode__(self):
+ return unicode(self.role or '')
diff --git a/rattail/django/rattail/models/contact.py b/rattail/django/rattail/models/contact.py
index 078d8e9..11bf429 100644
--- a/rattail/django/rattail/models/contact.py
+++ b/rattail/django/rattail/models/contact.py
@@ -33,7 +33,8 @@ from django.db import models
from rattail.django.rattail.models import Model, uuid_field
-__all__ = ['PhoneNumber', 'EmailAddress']
+__all__ = ['PhoneNumber', 'EmailAddress',
+ 'Person', 'PersonPhoneNumber', 'PersonEmailAddress']
class ContactInfoManager(models.Manager):
@@ -68,6 +69,8 @@ class PhoneNumber(ContactInfo):
class Meta(ContactInfo.Meta):
abstract = True
db_table = ContactInfo.prefix('phone_numbers')
+ verbose_name = "Phone Number"
+ verbose_name_plural = "Phone Numbers"
number = models.CharField(max_length=20)
@@ -86,6 +89,8 @@ class EmailAddress(ContactInfo):
class Meta(ContactInfo.Meta):
abstract = True
db_table = ContactInfo.prefix('email_addresses')
+ verbose_name = "Email Address"
+ verbose_name_plural = "Email Addresses"
address = models.CharField(max_length=255)
@@ -94,3 +99,63 @@ class EmailAddress(ContactInfo):
def __unicode__(self):
return unicode(self.address)
+
+
+class Person(Model):
+ """
+ Represents a real, living and breathing person. (Or, at least was
+ previously living and breathing, in the case of the deceased.)
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('people')
+ verbose_name_plural = "People"
+
+ uuid = uuid_field()
+ first_name = models.CharField(max_length=50, blank=True, null=True)
+ last_name = models.CharField(max_length=50, blank=True, null=True)
+ display_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Display Name")
+
+ def __repr__(self):
+ return "" % self.display_name
+
+ def __unicode__(self):
+ return unicode(self.display_name or '')
+
+ def save(self, *args, **kwargs):
+ if not self.display_name:
+ if self.first_name and self.last_name:
+ self.display_name = self.first_name + ' ' + self.last_name
+ elif self.first_name:
+ self.display_name = self.first_name
+ elif self.last_name:
+ self.display_name = self.last_name
+ super(Person, self).save(*args, **kwargs)
+
+
+class PersonContactInfo(models.Model):
+ """
+ Base class for person contact models (phone number, etc.).
+ """
+
+ class Meta:
+ abstract = True
+
+ store = models.ForeignKey(Person, db_column='parent_uuid')
+ objects = ContactInfoManager('Person')
+
+ def save(self, *args, **kwargs):
+ self.parent_type = 'Person'
+ super(PersonContactInfo, self).save(*args, **kwargs)
+
+
+class PersonPhoneNumber(PhoneNumber, PersonContactInfo):
+ """
+ Represents a phone (or fax) number associated with a :class:`Person`.
+ """
+
+
+class PersonEmailAddress(EmailAddress, PersonContactInfo):
+ """
+ Represents an email address associated with a :class:`Person`.
+ """
diff --git a/rattail/django/rattail/models/rattail.py b/rattail/django/rattail/models/rattail.py
index e12a22d..76dd036 100644
--- a/rattail/django/rattail/models/rattail.py
+++ b/rattail/django/rattail/models/rattail.py
@@ -30,8 +30,12 @@ from __future__ import absolute_import
from django.db import models
+from edbob.db.extensions.contact.enum import EMAIL_PREFERENCE
+
import rattail
from rattail.gpc import GPC
+from rattail.db.extension.enum import EMPLOYEE_STATUS
+
from rattail.django.rattail.models import Model, uuid_field
from rattail.django.rattail.models.contact import (
ContactInfoManager, PhoneNumber, EmailAddress)
@@ -40,7 +44,12 @@ from rattail.django.util import enum_to_choices
__all__ = ['Store', 'StorePhoneNumber', 'StoreEmailAddress',
'Department', 'Subdepartment', 'Category', 'Brand',
- 'Product', 'ProductPrice']
+ 'Vendor', 'VendorPhoneNumber', 'VendorEmailAddress', 'VendorContact',
+ 'Product', 'ProductPrice', 'ProductCost',
+ 'Employee', 'EmployeePhoneNumber', 'EmployeeEmailAddress',
+ 'Customer', 'CustomerPhoneNumber', 'CustomerEmailAddress', 'CustomerPerson',
+ 'CustomerGroup', 'CustomerGroupAssignment',
+ 'LabelProfile']
class GPCField(models.BigIntegerField):
@@ -70,6 +79,7 @@ class Store(Model):
class Meta(Model.Meta):
db_table = Model.prefix('stores')
+ verbose_name = "Store"
uuid = uuid_field()
id = models.CharField(max_length=10, blank=True, null=True, verbose_name="ID")
@@ -117,6 +127,7 @@ class Department(Model):
class Meta(Model.Meta):
db_table = Model.prefix('departments')
+ verbose_name = "Department"
uuid = uuid_field()
number = models.IntegerField(blank=True, null=True)
@@ -136,6 +147,7 @@ class Subdepartment(Model):
class Meta(Model.Meta):
db_table = Model.prefix('subdepartments')
+ verbose_name = "Subdepartment"
uuid = uuid_field()
number = models.IntegerField(blank=True, null=True)
@@ -156,6 +168,7 @@ class Category(Model):
class Meta(Model.Meta):
db_table = Model.prefix('categories')
+ verbose_name = "Category"
verbose_name_plural = "Categories"
uuid = uuid_field()
@@ -177,6 +190,7 @@ class Brand(Model):
class Meta(Model.Meta):
db_table = Model.prefix('brands')
+ verbose_name = "Brand"
uuid = uuid_field()
name = models.CharField(max_length=100, blank=True, null=True)
@@ -188,6 +202,77 @@ class Brand(Model):
return unicode(self.name or '')
+class Vendor(Model):
+ """
+ Represents a vendor from which products are purchased by the store.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('vendors')
+ verbose_name = "Vendor"
+
+ uuid = uuid_field()
+ id = models.CharField(max_length=15, blank=True, null=True, verbose_name="ID")
+ name = models.CharField(max_length=40, blank=True, null=True)
+ special_discount = models.DecimalField(max_digits=5, decimal_places=3, blank=True, null=True, verbose_name="Special Discount")
+
+ def __repr__(self):
+ return "" % self.name
+
+ def __unicode__(self):
+ return unicode(self.name or '')
+
+
+class VendorContactInfo(models.Model):
+ """
+ Base class for vendor contact models (phone number, etc.).
+ """
+
+ class Meta:
+ abstract = True
+
+ vendor = models.ForeignKey(Vendor, db_column='parent_uuid')
+ objects = ContactInfoManager('Vendor')
+
+ def save(self, *args, **kwargs):
+ self.parent_type = 'Vendor'
+ super(VendorContactInfo, self).save(*args, **kwargs)
+
+
+class VendorPhoneNumber(PhoneNumber, VendorContactInfo):
+ """
+ Represents a phone (or fax) number associated with a :class:`Vendor`.
+ """
+
+
+class VendorEmailAddress(EmailAddress, VendorContactInfo):
+ """
+ Represents an email address associated with a :class:`Vendor`.
+ """
+
+
+class VendorContact(Model):
+ """
+ Represents a point of contact (e.g. salesperson) for a vendor, from the
+ retailer's perspective.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('vendor_contacts')
+ verbose_name = "Vendor Contact"
+
+ uuid = uuid_field()
+ vendor = models.ForeignKey(Vendor, db_column='vendor_uuid')
+ person = models.ForeignKey('Person', db_column='person_uuid')
+ preference = models.IntegerField()
+
+ def __repr__(self):
+ return "" % (self.vendor, self.person)
+
+ def __unicode__(self):
+ return unicode(self.person)
+
+
class Product(Model):
"""
Represents a product for sale and/or purchase.
@@ -195,6 +280,9 @@ class Product(Model):
class Meta(Model.Meta):
db_table = Model.prefix('products')
+ verbose_name = "Product"
+
+ UNIT_OF_MEASURE_CHOICES = enum_to_choices(rattail.UNIT_OF_MEASURE)
uuid = uuid_field()
upc = GPCField(db_index=True, verbose_name="UPC")
@@ -205,7 +293,9 @@ class Product(Model):
description = models.CharField(max_length=60, blank=True, null=True)
description2 = models.CharField(max_length=60, blank=True, null=True, verbose_name="Description Line 2")
size = models.CharField(max_length=30, blank=True, null=True)
- unit_of_measure = models.CharField(max_length=4, blank=True, null=True, verbose_name="Unit of Measure")
+ unit_of_measure = models.CharField(max_length=4, choices=UNIT_OF_MEASURE_CHOICES, blank=True, null=True, verbose_name="Unit of Measure")
+ regular_price = models.ForeignKey('ProductPrice', db_column='regular_price_uuid', related_name='+', blank=True, null=True, verbose_name="Regular Price")
+ current_price = models.ForeignKey('ProductPrice', db_column='current_price_uuid', related_name='+', blank=True, null=True, verbose_name="Current Price")
def __repr__(self):
return "" % self.description
@@ -221,6 +311,7 @@ class ProductPrice(Model):
class Meta(Model.Meta):
db_table = Model.prefix('product_prices')
+ verbose_name = "Product Price"
PRICE_TYPE_CHOICES = enum_to_choices(rattail.PRICE_TYPE)
@@ -239,5 +330,243 @@ class ProductPrice(Model):
return "" % (self.product, self.price)
def __unicode__(self):
+ if self.price is None:
+ return u''
type = rattail.PRICE_TYPE.get(self.type, "?")
return u'$ %0.2f / %d (%s)' % (self.price, self.multiple or 1, type)
+
+
+class ProductCost(Model):
+ """
+ Represents a source from which a product may be obtained via purchase.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('product_costs')
+ verbose_name = "Product Cost"
+
+ uuid = uuid_field()
+ product = models.ForeignKey(Product, db_column='product_uuid')
+ vendor = models.ForeignKey(Vendor, db_column='vendor_uuid')
+ preference = models.IntegerField()
+ code = models.CharField(max_length=15, blank=True, null=True)
+ case_size = models.IntegerField(blank=True, null=True, verbose_name="Case Size")
+ case_cost = models.DecimalField(max_digits=9, decimal_places=5, blank=True, null=True, verbose_name="Case Cost")
+ pack_size = models.IntegerField(blank=True, null=True, verbose_name="Pack Size")
+ pack_cost = models.DecimalField(max_digits=9, decimal_places=5, blank=True, null=True, verbose_name="Pack Cost")
+ unit_cost = models.DecimalField(max_digits=9, decimal_places=5, blank=True, null=True, verbose_name="Unit Cost")
+ effective = models.DateTimeField(blank=True, null=True)
+
+ def __repr__(self):
+ return "" % (self.product, self.vendor)
+
+ def __unicode__(self):
+ if self.unit_cost is None:
+ return u''
+ return '$ %0.4f (%s)' % (self.unit_cost, self.vendor)
+
+
+class Employee(Model):
+ """
+ Represents an employee within the organization.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('employees')
+ verbose_name = "Employee"
+
+ EMPLOYEE_STATUS_CHOICES = enum_to_choices(EMPLOYEE_STATUS)
+
+ uuid = uuid_field()
+ id = models.IntegerField(blank=True, null=True, verbose_name="ID")
+ person = models.ForeignKey('Person', db_column='person_uuid')
+ status = models.IntegerField(choices=EMPLOYEE_STATUS_CHOICES)
+ display_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Display Name")
+
+ def __repr__(self):
+ return "" % self.person
+
+ def __unicode__(self):
+ return unicode(self.display_name or self.person)
+
+ def save(self, *args, **kwargs):
+ if not self.display_name and self.person:
+ if self.person.display_name:
+ self.display_name = self.person.display_name
+ elif self.person.first_name and self.person.last_name:
+ self.display_name = self.person.first_name + ' ' + self.person.last_name
+ elif self.person.first_name:
+ self.display_name = self.person.first_name
+ elif self.person.last_name:
+ self.display_name = self.person.last_name
+ super(Employee, self).save(*args, **kwargs)
+
+
+class EmployeeContactInfo(models.Model):
+ """
+ Base class for employee contact models (phone number, etc.).
+ """
+
+ class Meta:
+ abstract = True
+
+ employee = models.ForeignKey(Employee, db_column='parent_uuid')
+ objects = ContactInfoManager('Employee')
+
+ def save(self, *args, **kwargs):
+ self.parent_type = 'Employee'
+ super(EmployeeContactInfo, self).save(*args, **kwargs)
+
+
+class EmployeePhoneNumber(PhoneNumber, EmployeeContactInfo):
+ """
+ Represents a phone (or fax) number associated with a :class:`Employee`.
+ """
+
+
+class EmployeeEmailAddress(EmailAddress, EmployeeContactInfo):
+ """
+ Represents an email address associated with a :class:`Employee`.
+ """
+
+
+class Customer(Model):
+ """
+ Represents a customer account. Customer accounts may consist of more than
+ one :class:`Person`, in some cases.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('customers')
+ verbose_name = "Customer"
+
+ EMAIL_PREFERENCE_CHOICES = enum_to_choices(EMAIL_PREFERENCE)
+
+ uuid = uuid_field()
+ id = models.CharField(max_length=20, null=True, blank=True, verbose_name="ID")
+ name = models.CharField(max_length=255, null=True, blank=True)
+ email_preference = models.IntegerField(choices=EMAIL_PREFERENCE_CHOICES, null=True, blank=True, verbose_name="Email Preference")
+
+ def __repr__(self):
+ return "" % (self.id, self.name)
+
+ def __unicode__(self):
+ return unicode(self.name or '')
+
+
+class CustomerContactInfo(models.Model):
+ """
+ Base class for customer contact models (phone number, etc.).
+ """
+
+ class Meta:
+ abstract = True
+
+ customer = models.ForeignKey(Customer, db_column='parent_uuid')
+ objects = ContactInfoManager('Customer')
+
+ def save(self, *args, **kwargs):
+ self.parent_type = 'Customer'
+ super(CustomerContactInfo, self).save(*args, **kwargs)
+
+
+class CustomerPhoneNumber(PhoneNumber, CustomerContactInfo):
+ """
+ Represents a phone (or fax) number associated with a :class:`Customer`.
+ """
+
+
+class CustomerEmailAddress(EmailAddress, CustomerContactInfo):
+ """
+ Represents an email address associated with a :class:`Customer`.
+ """
+
+
+class CustomerPerson(Model):
+ """
+ Represents the association between a :class:`Person` and a customer account
+ (:class:`Customer`).
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('customers_people')
+ verbose_name = "Customer Person"
+
+ uuid = uuid_field()
+ customer = models.ForeignKey(Customer, db_column='customer_uuid')
+ person = models.ForeignKey('Person', db_column='person_uuid')
+ ordinal = models.IntegerField()
+
+ def __repr__(self):
+ return "" % self.person
+
+ def __unicode__(self):
+ return unicode(self.person or '')
+
+
+class CustomerGroup(Model):
+ """
+ Represents an arbitrary group to which :class:`Customer` instances may (or
+ may not) belong.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('customer_groups')
+ verbose_name = "Customer Group"
+
+ uuid = uuid_field()
+ id = models.CharField(max_length=20, blank=True, null=True, verbose_name="ID")
+ name = models.CharField(max_length=255, blank=True, null=True)
+
+ def __repr__(self):
+ return "" % (self.id, self.name)
+
+ def __unicode__(self):
+ return unicode(self.name or '')
+
+
+class CustomerGroupAssignment(Model):
+ """
+ Represents the assignment of a :class:`Customer` to a
+ :class:`CustomerGroup`.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('customers_groups')
+ verbose_name = "Customer Group Assignment"
+
+ uuid = uuid_field()
+ customer = models.ForeignKey(Customer, db_column='customer_uuid')
+ group = models.ForeignKey(CustomerGroup, db_column='group_uuid')
+ ordinal = models.IntegerField()
+
+ def __repr__(self):
+ return "" % (self.customer, self.group)
+
+ def __unicode__(self):
+ return u'%s, %s' % (self.customer, self.group)
+
+
+class LabelProfile(Model):
+ """
+ Represents a "profile" (collection of settings) for product label printing.
+ """
+
+ class Meta(Model.Meta):
+ db_table = Model.prefix('label_profiles')
+ verbose_name = "Label Profile"
+
+ uuid = uuid_field()
+ ordinal = models.IntegerField(blank=True, null=True)
+ code = models.CharField(max_length=3, blank=True, null=True)
+ description = models.CharField(max_length=50, blank=True, null=True)
+ printer_spec = models.CharField(max_length=255, blank=True, null=True, verbose_name="Printer Spec")
+ formatter_spec = models.CharField(max_length=255, blank=True, null=True, verbose_name="Formatter Spec")
+ format = models.TextField(blank=True, null=True)
+ visible = models.BooleanField()
+
+ def __repr__(self):
+ return "" % self.code
+
+ def __unicode__(self):
+ return unicode(self.description or '')