um..a bunch more changes (savepoint)
This commit is contained in:
parent
d8b8a7852b
commit
88fc224abc
|
@ -50,14 +50,27 @@ class ContactInfoInline(admin.TabularInline):
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
class PartyInline(admin.TabularInline):
|
||||||
|
"""
|
||||||
|
Base inline manager for all party models.
|
||||||
|
"""
|
||||||
|
|
||||||
|
exclude = ('uuid', 'parent_type')
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class PersonPhoneNumberInline(ContactInfoInline):
|
class PersonPhoneNumberInline(ContactInfoInline):
|
||||||
model = PersonPhoneNumber
|
model = PersonPhoneNumber
|
||||||
|
|
||||||
class PersonEmailAddressInline(ContactInfoInline):
|
class PersonEmailAddressInline(ContactInfoInline):
|
||||||
model = PersonEmailAddress
|
model = PersonEmailAddress
|
||||||
|
|
||||||
|
class PersonPostalAddressInline(ContactInfoInline):
|
||||||
|
model = PersonPostalAddress
|
||||||
|
|
||||||
class PersonAdmin(ModelAdmin):
|
class PersonAdmin(ModelAdmin):
|
||||||
inlines = [PersonPhoneNumberInline, PersonEmailAddressInline]
|
inlines = [PersonPhoneNumberInline, PersonEmailAddressInline,
|
||||||
|
PersonPostalAddressInline]
|
||||||
|
|
||||||
def get_formsets(self, request, obj=None):
|
def get_formsets(self, request, obj=None):
|
||||||
for inline in self.get_inline_instances(request):
|
for inline in self.get_inline_instances(request):
|
||||||
|
@ -97,8 +110,12 @@ class StorePhoneNumberInline(ContactInfoInline):
|
||||||
class StoreEmailAddressInline(ContactInfoInline):
|
class StoreEmailAddressInline(ContactInfoInline):
|
||||||
model = StoreEmailAddress
|
model = StoreEmailAddress
|
||||||
|
|
||||||
|
class StorePostalAddressInline(ContactInfoInline):
|
||||||
|
model = StorePostalAddress
|
||||||
|
|
||||||
class StoreAdmin(ModelAdmin):
|
class StoreAdmin(ModelAdmin):
|
||||||
inlines = [StorePhoneNumberInline, StoreEmailAddressInline]
|
inlines = [StorePhoneNumberInline, StoreEmailAddressInline,
|
||||||
|
StorePostalAddressInline]
|
||||||
|
|
||||||
def get_formsets(self, request, obj=None):
|
def get_formsets(self, request, obj=None):
|
||||||
for inline in self.get_inline_instances(request):
|
for inline in self.get_inline_instances(request):
|
||||||
|
@ -127,22 +144,21 @@ class VendorPhoneNumberInline(ContactInfoInline):
|
||||||
class VendorEmailAddressInline(ContactInfoInline):
|
class VendorEmailAddressInline(ContactInfoInline):
|
||||||
model = VendorEmailAddress
|
model = VendorEmailAddress
|
||||||
|
|
||||||
class VendorContactInline(admin.TabularInline):
|
class VendorPostalAddressInline(ContactInfoInline):
|
||||||
model = VendorContact
|
model = VendorPostalAddress
|
||||||
verbose_name = "Contact"
|
|
||||||
verbose_name_plural = "Contacts"
|
class VendorPartyInline(PartyInline):
|
||||||
exclude = ('uuid',)
|
model = VendorParty
|
||||||
extra = 0
|
|
||||||
|
|
||||||
class VendorAdmin(ModelAdmin):
|
class VendorAdmin(ModelAdmin):
|
||||||
inlines = [VendorPhoneNumberInline, VendorEmailAddressInline,
|
inlines = [VendorPhoneNumberInline, VendorEmailAddressInline,
|
||||||
VendorContactInline]
|
VendorPostalAddressInline, VendorPartyInline]
|
||||||
|
|
||||||
def get_formsets(self, request, obj=None):
|
def get_formsets(self, request, obj=None):
|
||||||
for inline in self.get_inline_instances(request):
|
for inline in self.get_inline_instances(request):
|
||||||
if isinstance(inline, ContactInfoInline) and obj is None:
|
if isinstance(inline, ContactInfoInline) and obj is None:
|
||||||
continue
|
continue
|
||||||
if isinstance(inline, VendorContactInline) and obj is None:
|
if isinstance(inline, PartyInline) and obj is None:
|
||||||
continue
|
continue
|
||||||
yield inline.get_formset(request, obj)
|
yield inline.get_formset(request, obj)
|
||||||
|
|
||||||
|
@ -188,22 +204,7 @@ class ProductAdmin(ModelAdmin):
|
||||||
admin.site.register(Product, ProductAdmin)
|
admin.site.register(Product, ProductAdmin)
|
||||||
|
|
||||||
|
|
||||||
class EmployeePhoneNumberInline(ContactInfoInline):
|
admin.site.register(Employee, ModelAdmin)
|
||||||
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)
|
admin.site.register(CustomerGroup, ModelAdmin)
|
||||||
|
@ -215,6 +216,9 @@ class CustomerPhoneNumberInline(ContactInfoInline):
|
||||||
class CustomerEmailAddressInline(ContactInfoInline):
|
class CustomerEmailAddressInline(ContactInfoInline):
|
||||||
model = CustomerEmailAddress
|
model = CustomerEmailAddress
|
||||||
|
|
||||||
|
class CustomerPostalAddressInline(ContactInfoInline):
|
||||||
|
model = CustomerPostalAddress
|
||||||
|
|
||||||
class CustomerGroupAssignmentInline(admin.TabularInline):
|
class CustomerGroupAssignmentInline(admin.TabularInline):
|
||||||
model = CustomerGroupAssignment
|
model = CustomerGroupAssignment
|
||||||
verbose_name = "Group Assignment"
|
verbose_name = "Group Assignment"
|
||||||
|
@ -222,9 +226,13 @@ class CustomerGroupAssignmentInline(admin.TabularInline):
|
||||||
exclude = ('uuid',)
|
exclude = ('uuid',)
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
class CustomerPartyInline(PartyInline):
|
||||||
|
model = CustomerParty
|
||||||
|
|
||||||
class CustomerAdmin(ModelAdmin):
|
class CustomerAdmin(ModelAdmin):
|
||||||
inlines = [CustomerPhoneNumberInline, CustomerEmailAddressInline,
|
inlines = [CustomerPhoneNumberInline, CustomerEmailAddressInline,
|
||||||
CustomerGroupAssignmentInline]
|
CustomerPostalAddressInline, CustomerGroupAssignmentInline,
|
||||||
|
CustomerPartyInline]
|
||||||
|
|
||||||
def get_formsets(self, request, obj=None):
|
def get_formsets(self, request, obj=None):
|
||||||
for inline in self.get_inline_instances(request):
|
for inline in self.get_inline_instances(request):
|
||||||
|
@ -232,6 +240,8 @@ class CustomerAdmin(ModelAdmin):
|
||||||
continue
|
continue
|
||||||
if isinstance(inline, CustomerGroupAssignmentInline) and obj is None:
|
if isinstance(inline, CustomerGroupAssignmentInline) and obj is None:
|
||||||
continue
|
continue
|
||||||
|
if isinstance(inline, PartyInline) and obj is None:
|
||||||
|
continue
|
||||||
yield inline.get_formset(request, obj)
|
yield inline.get_formset(request, obj)
|
||||||
|
|
||||||
admin.site.register(Customer, CustomerAdmin)
|
admin.site.register(Customer, CustomerAdmin)
|
||||||
|
|
|
@ -12,8 +12,11 @@ class Migration(SchemaMigration):
|
||||||
db.create_table('rattail_people', (
|
db.create_table('rattail_people', (
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('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)),
|
('first_name', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True)),
|
||||||
|
('middle_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)),
|
('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)),
|
('display_name', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
|
||||||
|
('driver_license_state', self.gf('django.db.models.fields.CharField')(max_length=4, null=True, blank=True)),
|
||||||
|
('driver_license_number', self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True)),
|
||||||
))
|
))
|
||||||
db.send_create_signal('rattail', ['Person'])
|
db.send_create_signal('rattail', ['Person'])
|
||||||
|
|
||||||
|
@ -22,7 +25,7 @@ class Migration(SchemaMigration):
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||||
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
||||||
('preference', self.gf('django.db.models.fields.IntegerField')()),
|
('preference', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||||
('type', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
|
('type', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
|
||||||
('number', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
('number', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||||
))
|
))
|
||||||
|
@ -33,12 +36,38 @@ class Migration(SchemaMigration):
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||||
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
||||||
('preference', self.gf('django.db.models.fields.IntegerField')()),
|
('preference', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||||
('type', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
|
('type', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
|
||||||
('address', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
('address', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||||
))
|
))
|
||||||
db.send_create_signal('rattail', ['EmailAddress'])
|
db.send_create_signal('rattail', ['EmailAddress'])
|
||||||
|
|
||||||
|
# Adding model 'PostalAddress'
|
||||||
|
db.create_table('rattail_postal_addresses', (
|
||||||
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
|
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||||
|
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
||||||
|
('preference', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||||
|
('type', self.gf('django.db.models.fields.CharField')(max_length=15, null=True, blank=True)),
|
||||||
|
('street', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
|
||||||
|
('street2', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
|
||||||
|
('city', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
|
||||||
|
('state', self.gf('django.db.models.fields.CharField')(max_length=2, null=True, blank=True)),
|
||||||
|
('zipcode', self.gf('django.db.models.fields.CharField')(max_length=10, null=True, blank=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('rattail', ['PostalAddress'])
|
||||||
|
|
||||||
|
# Adding model 'Party'
|
||||||
|
db.create_table('rattail_parties', (
|
||||||
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
|
('parent_type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||||
|
('parent_uuid', self.gf('django.db.models.fields.CharField')(max_length=32)),
|
||||||
|
('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], db_column='person_uuid')),
|
||||||
|
('type', self.gf('django.db.models.fields.CharField')(max_length=25, null=True, blank=True)),
|
||||||
|
('preference', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('rattail', ['Party'])
|
||||||
|
|
||||||
# Adding model 'Role'
|
# Adding model 'Role'
|
||||||
db.create_table('rattail_roles', (
|
db.create_table('rattail_roles', (
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
|
@ -114,15 +143,6 @@ class Migration(SchemaMigration):
|
||||||
))
|
))
|
||||||
db.send_create_signal('rattail', ['Vendor'])
|
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'
|
# Adding model 'Product'
|
||||||
db.create_table('rattail_products', (
|
db.create_table('rattail_products', (
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
|
@ -174,9 +194,9 @@ class Migration(SchemaMigration):
|
||||||
# Adding model 'Employee'
|
# Adding model 'Employee'
|
||||||
db.create_table('rattail_employees', (
|
db.create_table('rattail_employees', (
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('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)),
|
('id', self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True)),
|
||||||
('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['rattail.Person'], db_column='person_uuid')),
|
('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')()),
|
('status', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||||
('display_name', self.gf('django.db.models.fields.CharField')(max_length=100, 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', ['Employee'])
|
db.send_create_signal('rattail', ['Employee'])
|
||||||
|
@ -190,15 +210,6 @@ class Migration(SchemaMigration):
|
||||||
))
|
))
|
||||||
db.send_create_signal('rattail', ['Customer'])
|
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'
|
# Adding model 'CustomerGroup'
|
||||||
db.create_table('rattail_customer_groups', (
|
db.create_table('rattail_customer_groups', (
|
||||||
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
('uuid', self.gf('rattail.django.rattail.models.core.UUIDField')(max_length=32, primary_key=True)),
|
||||||
|
@ -240,9 +251,6 @@ class Migration(SchemaMigration):
|
||||||
# Deleting model 'CustomerGroup'
|
# Deleting model 'CustomerGroup'
|
||||||
db.delete_table('rattail_customer_groups')
|
db.delete_table('rattail_customer_groups')
|
||||||
|
|
||||||
# Deleting model 'CustomerPerson'
|
|
||||||
db.delete_table('rattail_customers_people')
|
|
||||||
|
|
||||||
# Deleting model 'Customer'
|
# Deleting model 'Customer'
|
||||||
db.delete_table('rattail_customers')
|
db.delete_table('rattail_customers')
|
||||||
|
|
||||||
|
@ -258,9 +266,6 @@ class Migration(SchemaMigration):
|
||||||
# Deleting model 'Product'
|
# Deleting model 'Product'
|
||||||
db.delete_table('rattail_products')
|
db.delete_table('rattail_products')
|
||||||
|
|
||||||
# Deleting model 'VendorContact'
|
|
||||||
db.delete_table('rattail_vendor_contacts')
|
|
||||||
|
|
||||||
# Deleting model 'Vendor'
|
# Deleting model 'Vendor'
|
||||||
db.delete_table('rattail_vendors')
|
db.delete_table('rattail_vendors')
|
||||||
|
|
||||||
|
@ -288,6 +293,12 @@ class Migration(SchemaMigration):
|
||||||
# Deleting model 'Role'
|
# Deleting model 'Role'
|
||||||
db.delete_table('rattail_roles')
|
db.delete_table('rattail_roles')
|
||||||
|
|
||||||
|
# Deleting model 'Party'
|
||||||
|
db.delete_table('rattail_parties')
|
||||||
|
|
||||||
|
# Deleting model 'PostalAddress'
|
||||||
|
db.delete_table('rattail_postal_addresses')
|
||||||
|
|
||||||
# Deleting model 'EmailAddress'
|
# Deleting model 'EmailAddress'
|
||||||
db.delete_table('rattail_email_addresses')
|
db.delete_table('rattail_email_addresses')
|
||||||
|
|
||||||
|
@ -302,7 +313,10 @@ class Migration(SchemaMigration):
|
||||||
'rattail.person': {
|
'rattail.person': {
|
||||||
'Meta': {'object_name': 'Person', 'db_table': "'rattail_people'"},
|
'Meta': {'object_name': 'Person', 'db_table': "'rattail_people'"},
|
||||||
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'driver_license_state': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'driver_license_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
|
||||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'middle_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'}),
|
'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'})
|
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
|
||||||
},
|
},
|
||||||
|
@ -311,7 +325,7 @@ class Migration(SchemaMigration):
|
||||||
'number': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
'number': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
||||||
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
||||||
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||||
'preference': ('django.db.models.fields.IntegerField', [], {}),
|
'preference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
|
'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'})
|
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
|
||||||
},
|
},
|
||||||
|
@ -320,10 +334,32 @@ class Migration(SchemaMigration):
|
||||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
||||||
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||||
'preference': ('django.db.models.fields.IntegerField', [], {}),
|
'preference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
|
'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'})
|
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
|
||||||
},
|
},
|
||||||
|
'rattail.postaladdress': {
|
||||||
|
'Meta': {'object_name': 'PostalAddress', 'db_table': "'rattail_postal_addresses'"},
|
||||||
|
'city': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
||||||
|
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||||
|
'preference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'state': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'street': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'street2': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'rattail.party': {
|
||||||
|
'Meta': {'object_name': 'Party', 'db_table': "'rattail_parties'"},
|
||||||
|
'parent_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
|
||||||
|
'parent_uuid': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||||
|
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
|
||||||
|
'preference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'}),
|
||||||
|
},
|
||||||
'rattail.role': {
|
'rattail.role': {
|
||||||
'Meta': {'object_name': 'Role', 'db_table': "'rattail_roles'"},
|
'Meta': {'object_name': 'Role', 'db_table': "'rattail_roles'"},
|
||||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
|
||||||
|
@ -381,13 +417,6 @@ class Migration(SchemaMigration):
|
||||||
'special_discount': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '3', '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'})
|
'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': {
|
'rattail.product': {
|
||||||
'Meta': {'object_name': 'Product', 'db_table': "'rattail_products'"},
|
'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'}),
|
'brand': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Brand']", 'null': 'True', 'db_column': "'brand_uuid'", 'blank': 'True'}),
|
||||||
|
@ -433,9 +462,9 @@ class Migration(SchemaMigration):
|
||||||
'rattail.employee': {
|
'rattail.employee': {
|
||||||
'Meta': {'object_name': 'Employee', 'db_table': "'rattail_employees'"},
|
'Meta': {'object_name': 'Employee', 'db_table': "'rattail_employees'"},
|
||||||
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
'id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
'id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
|
||||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
|
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rattail.Person']", 'db_column': "'person_uuid'"}),
|
||||||
'status': ('django.db.models.fields.IntegerField', [], {}),
|
'status': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
|
'uuid': ('rattail.django.rattail.models.core.UUIDField', [], {'max_length': '32', 'primary_key': 'True'})
|
||||||
},
|
},
|
||||||
'rattail.customer': {
|
'rattail.customer': {
|
||||||
|
@ -445,13 +474,6 @@ class Migration(SchemaMigration):
|
||||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', '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'})
|
'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': {
|
'rattail.customergroup': {
|
||||||
'Meta': {'object_name': 'CustomerGroup', 'db_table': "'rattail_customer_groups'"},
|
'Meta': {'object_name': 'CustomerGroup', 'db_table': "'rattail_customer_groups'"},
|
||||||
'id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
|
'id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
|
||||||
|
|
|
@ -29,12 +29,14 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from rattail.django.rattail.models import Model, uuid_field
|
from rattail.django.rattail.models import Model, uuid_field
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['PhoneNumber', 'EmailAddress',
|
__all__ = ['Contact', 'PhoneNumber', 'EmailAddress', 'PostalAddress',
|
||||||
'Person', 'PersonPhoneNumber', 'PersonEmailAddress']
|
'Person', 'PersonPhoneNumber', 'PersonEmailAddress', 'PersonPostalAddress',
|
||||||
|
'Party']
|
||||||
|
|
||||||
|
|
||||||
class ContactInfoManager(models.Manager):
|
class ContactInfoManager(models.Manager):
|
||||||
|
@ -57,7 +59,7 @@ class ContactInfo(Model):
|
||||||
|
|
||||||
uuid = uuid_field()
|
uuid = uuid_field()
|
||||||
parent_type = models.CharField(max_length=20)
|
parent_type = models.CharField(max_length=20)
|
||||||
preference = models.IntegerField()
|
preference = models.IntegerField(blank=True, null=True)
|
||||||
type = models.CharField(max_length=15, blank=True, null=True)
|
type = models.CharField(max_length=15, blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,20 +103,223 @@ class EmailAddress(ContactInfo):
|
||||||
return unicode(self.address)
|
return unicode(self.address)
|
||||||
|
|
||||||
|
|
||||||
class Person(Model):
|
class PostalAddress(ContactInfo):
|
||||||
|
"""
|
||||||
|
Represents a postal (mailing) address associated with a contactable entity.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta(ContactInfo.Meta):
|
||||||
|
abstract = True
|
||||||
|
db_table = ContactInfo.prefix('postal_addresses')
|
||||||
|
verbose_name = "Postal Address"
|
||||||
|
verbose_name_plural = "Postal Addresses"
|
||||||
|
|
||||||
|
street = models.CharField(max_length=100, blank=True, null=True)
|
||||||
|
street2 = models.CharField(max_length=100, blank=True, null=True)
|
||||||
|
city = models.CharField(max_length=100, blank=True, null=True)
|
||||||
|
state = models.CharField(max_length=2, blank=True, null=True)
|
||||||
|
zipcode = models.CharField(max_length=10, blank=True, null=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s: %s>" % (self.__class__.__name__, self.street)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.street)
|
||||||
|
|
||||||
|
|
||||||
|
class Contact(Model):
|
||||||
|
"""
|
||||||
|
Base class for models which may be associated with contact info data.
|
||||||
|
|
||||||
|
This class exists only to define convenience methods and properties on the
|
||||||
|
derived class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta(Model.Meta):
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Contact, self).__init__(*args, **kwargs)
|
||||||
|
self._phones = {}
|
||||||
|
self._emails = {}
|
||||||
|
self._addresses = {}
|
||||||
|
self._preferred = {}
|
||||||
|
|
||||||
|
def _translate_info_class(self, class_):
|
||||||
|
from rattail.django.rattail import models
|
||||||
|
class_name = self.__class__.__name__ + class_.__name__
|
||||||
|
if hasattr(models, class_name):
|
||||||
|
class_ = getattr(models, class_name)
|
||||||
|
return class_
|
||||||
|
|
||||||
|
def _filter_queryset(self, qs):
|
||||||
|
parent = self.__class__.__name__.lower()
|
||||||
|
kwargs = {parent: self}
|
||||||
|
return qs.filter(**kwargs)
|
||||||
|
|
||||||
|
def _assign_parent(self, info):
|
||||||
|
parent = self.__class__.__name__.lower()
|
||||||
|
setattr(info, parent, self)
|
||||||
|
|
||||||
|
def _get_info_dict(self, class_):
|
||||||
|
if issubclass(class_, PhoneNumber):
|
||||||
|
return self._phones
|
||||||
|
elif issubclass(class_, EmailAddress):
|
||||||
|
return self._emails
|
||||||
|
elif issubclass(class_, PostalAddress):
|
||||||
|
return self._addresses
|
||||||
|
raise ValueError("Expected a subclass of ContactInfo; got %s" % class_.__name__)
|
||||||
|
|
||||||
|
def _get_info_key(self, class_):
|
||||||
|
if issubclass(class_, PhoneNumber):
|
||||||
|
return 'phone'
|
||||||
|
elif issubclass(class_, EmailAddress):
|
||||||
|
return 'email'
|
||||||
|
elif issubclass(class_, PostalAddress):
|
||||||
|
return 'address'
|
||||||
|
raise ValueError("Expected a subclass of ContactInfo; got %s" % class_.__name__)
|
||||||
|
|
||||||
|
def _get_info(self, class_, type, info_dict=None):
|
||||||
|
class_ = self._translate_info_class(class_)
|
||||||
|
if info_dict is None:
|
||||||
|
info_dict = self._get_info_dict(class_)
|
||||||
|
if type not in info_dict:
|
||||||
|
qs = class_.objects
|
||||||
|
qs = self._filter_queryset(qs)
|
||||||
|
qs = qs.filter(type=type)
|
||||||
|
try:
|
||||||
|
info = qs.get()
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
info = None
|
||||||
|
info_dict[type] = info
|
||||||
|
return info_dict[type]
|
||||||
|
|
||||||
|
def get_phone(self, type):
|
||||||
|
return self._get_info(PhoneNumber, type)
|
||||||
|
|
||||||
|
def get_email(self, type):
|
||||||
|
return self._get_info(EmailAddress, type)
|
||||||
|
|
||||||
|
def get_address(self, type):
|
||||||
|
return self._get_info(PostalAddress, type)
|
||||||
|
|
||||||
|
def _update_info(self, class_, type, data):
|
||||||
|
class_ = self._translate_info_class(class_)
|
||||||
|
info_dict = self._get_info_dict(class_)
|
||||||
|
info = self._get_info(class_, type, info_dict)
|
||||||
|
|
||||||
|
# Check data for values; if none exist then we'll delete the info.
|
||||||
|
values = False
|
||||||
|
for value in data.itervalues():
|
||||||
|
if value:
|
||||||
|
values = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if values:
|
||||||
|
if not info:
|
||||||
|
info = class_()
|
||||||
|
self._assign_parent(info)
|
||||||
|
info.type = type
|
||||||
|
info_dict[type] = info
|
||||||
|
for key, value in data.iteritems():
|
||||||
|
setattr(info, key, value)
|
||||||
|
info.save()
|
||||||
|
return info
|
||||||
|
|
||||||
|
if info:
|
||||||
|
info.delete()
|
||||||
|
info_dict[type] = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_phone(self, type, data):
|
||||||
|
return self._update_info(PhoneNumber, type, data)
|
||||||
|
|
||||||
|
def update_email(self, type, data):
|
||||||
|
return self._update_info(EmailAddress, type, data)
|
||||||
|
|
||||||
|
def update_address(self, type, data):
|
||||||
|
return self._update_info(PostalAddress, type, data)
|
||||||
|
|
||||||
|
def _get_preferred_info(self, class_):
|
||||||
|
class_ = self._translate_info_class(class_)
|
||||||
|
info_key = self._get_info_key(class_)
|
||||||
|
if info_key not in self._preferred:
|
||||||
|
qs = class_.objects
|
||||||
|
qs = self._filter_queryset(qs)
|
||||||
|
qs = qs.filter(preference=1)
|
||||||
|
try:
|
||||||
|
info = qs.get()
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
info = None
|
||||||
|
self._preferred[info_key] = info
|
||||||
|
return self._preferred[info_key]
|
||||||
|
|
||||||
|
def get_preferred_phone(self):
|
||||||
|
return self._get_preferred_info(PhoneNumber)
|
||||||
|
|
||||||
|
def get_preferred_email(self):
|
||||||
|
return self._get_preferred_info(EmailAddress)
|
||||||
|
|
||||||
|
def get_preferred_address(self):
|
||||||
|
return self._get_preferred_info(PostalAddress)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def phone(self):
|
||||||
|
return self.get_preferred_phone()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def email(self):
|
||||||
|
return self.get_preferred_email()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address(self):
|
||||||
|
return self.get_preferred_address()
|
||||||
|
|
||||||
|
def _set_preferred_info(self, class_, info):
|
||||||
|
class_ = self._translate_info_class(class_)
|
||||||
|
info_dict = self._get_info_dict(class_)
|
||||||
|
info_key = self._get_info_key(class_)
|
||||||
|
|
||||||
|
if info.preference != 1:
|
||||||
|
info.preference = 1
|
||||||
|
info.save()
|
||||||
|
self._preferred[info_key] = info
|
||||||
|
|
||||||
|
preference = 2
|
||||||
|
for other_info in sorted(info_dict.values(),
|
||||||
|
key=lambda x: x.preference if x else 999):
|
||||||
|
if other_info and other_info is not info:
|
||||||
|
other_info.preference = preference
|
||||||
|
other_info.save()
|
||||||
|
preference += 1
|
||||||
|
|
||||||
|
def set_preferred_phone(self, phone):
|
||||||
|
self._set_preferred_info(PhoneNumber, phone)
|
||||||
|
|
||||||
|
def set_preferred_email(self, email):
|
||||||
|
self._set_preferred_info(EmailAddress, email)
|
||||||
|
|
||||||
|
def set_preferred_address(self, address):
|
||||||
|
self._set_preferred_info(PostalAddress, address)
|
||||||
|
|
||||||
|
|
||||||
|
class Person(Contact):
|
||||||
"""
|
"""
|
||||||
Represents a real, living and breathing person. (Or, at least was
|
Represents a real, living and breathing person. (Or, at least was
|
||||||
previously living and breathing, in the case of the deceased.)
|
previously living and breathing, in the case of the deceased.)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta(Model.Meta):
|
class Meta(Contact.Meta):
|
||||||
db_table = Model.prefix('people')
|
db_table = Contact.prefix('people')
|
||||||
verbose_name_plural = "People"
|
verbose_name_plural = "People"
|
||||||
|
|
||||||
uuid = uuid_field()
|
uuid = uuid_field()
|
||||||
first_name = models.CharField(max_length=50, blank=True, null=True)
|
first_name = models.CharField(max_length=50, blank=True, null=True)
|
||||||
|
middle_name = models.CharField(max_length=50, blank=True, null=True)
|
||||||
last_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")
|
display_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Display Name")
|
||||||
|
driver_license_state = models.CharField(max_length=4, blank=True, null=True)
|
||||||
|
driver_license_number = models.CharField(max_length=20, blank=True, null=True)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Person: %s>" % self.display_name
|
return "<Person: %s>" % self.display_name
|
||||||
|
@ -122,16 +327,51 @@ class Person(Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.display_name or '')
|
return unicode(self.display_name or '')
|
||||||
|
|
||||||
|
def update_display_name(self):
|
||||||
|
orig_display_name = 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
|
||||||
|
return self.display_name != orig_display_name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.display_name:
|
if not self.display_name:
|
||||||
if self.first_name and self.last_name:
|
self.update_display_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)
|
super(Person, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
_employee = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def employee(self):
|
||||||
|
if self._employee is None:
|
||||||
|
from rattail.django.rattail.models import Employee
|
||||||
|
qs = Employee.objects
|
||||||
|
qs = qs.filter(person=self)
|
||||||
|
try:
|
||||||
|
self._employee = qs.get()
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
pass
|
||||||
|
return self._employee
|
||||||
|
|
||||||
|
def make_employee(self, **kwargs):
|
||||||
|
if self.employee:
|
||||||
|
return
|
||||||
|
|
||||||
|
from rattail.django.rattail.models import Employee
|
||||||
|
employee = Employee(**kwargs)
|
||||||
|
employee.person = self
|
||||||
|
employee.save()
|
||||||
|
self._employee = employee
|
||||||
|
return employee
|
||||||
|
|
||||||
|
def unmake_employee(self):
|
||||||
|
if self.employee:
|
||||||
|
self.employee.delete()
|
||||||
|
self._employee = None
|
||||||
|
|
||||||
|
|
||||||
class PersonContactInfo(models.Model):
|
class PersonContactInfo(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -141,7 +381,7 @@ class PersonContactInfo(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
store = models.ForeignKey(Person, db_column='parent_uuid')
|
person = models.ForeignKey(Person, db_column='parent_uuid')
|
||||||
objects = ContactInfoManager('Person')
|
objects = ContactInfoManager('Person')
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
@ -159,3 +399,44 @@ class PersonEmailAddress(EmailAddress, PersonContactInfo):
|
||||||
"""
|
"""
|
||||||
Represents an email address associated with a :class:`Person`.
|
Represents an email address associated with a :class:`Person`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PersonPostalAddress(PostalAddress, PersonContactInfo):
|
||||||
|
"""
|
||||||
|
Represents a postal (mailing) address associated with a :class:`Person`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PartyManager(models.Manager):
|
||||||
|
|
||||||
|
def __init__(self, parent_type):
|
||||||
|
super(PartyManager, self).__init__()
|
||||||
|
self.parent_type = parent_type
|
||||||
|
|
||||||
|
def get_query_set(self):
|
||||||
|
qs = super(PartyManager, self).get_query_set()
|
||||||
|
qs = qs.filter(parent_type=self.parent_type)
|
||||||
|
qs = qs.order_by('preference')
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
class Party(Model):
|
||||||
|
"""
|
||||||
|
Base class for "party" relationships, e.g. sales contacts for vendors and
|
||||||
|
authorized shoppers for customers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta(Model.Meta):
|
||||||
|
abstract = True
|
||||||
|
db_table = Model.prefix('parties')
|
||||||
|
verbose_name = "Party"
|
||||||
|
verbose_name_plural = "Parties"
|
||||||
|
|
||||||
|
uuid = uuid_field()
|
||||||
|
parent_type = models.CharField(max_length=20)
|
||||||
|
person = models.ForeignKey(Person, db_column='person_uuid')
|
||||||
|
type = models.CharField(max_length=25, blank=True, null=True)
|
||||||
|
preference = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s (%s)' % (self.person, self.type)
|
||||||
|
|
|
@ -32,7 +32,7 @@ from django.conf import settings
|
||||||
import edbob
|
import edbob
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['Model', 'uuid_field']
|
__all__ = ['Model', 'uuid_field', 'ProxyModel', 'PersonProxyModel']
|
||||||
|
|
||||||
|
|
||||||
class Model(models.Model):
|
class Model(models.Model):
|
||||||
|
@ -61,6 +61,80 @@ class Model(models.Model):
|
||||||
return table_name
|
return table_name
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyModel(models.Model):
|
||||||
|
"""
|
||||||
|
Base class for models which intend to "proxy" certain attributes to an
|
||||||
|
underlying Rattail model. This is designed for use in apps which use
|
||||||
|
Rattail as their primary schema but need to extend it in some way.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
_proxy_attribute_map = {}
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
for proxy, attrs in self.__class__._proxy_attribute_map.iteritems():
|
||||||
|
for attr in attrs:
|
||||||
|
if isinstance(attr, tuple):
|
||||||
|
convenient, actual = attr
|
||||||
|
else:
|
||||||
|
convenient = actual = attr
|
||||||
|
if convenient == name:
|
||||||
|
return getattr(getattr(self, proxy), actual)
|
||||||
|
return super(ProxyModel, self).__getattr__(name)
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
for proxy, attrs in self.__class__._proxy_attribute_map.iteritems():
|
||||||
|
for attr in attrs:
|
||||||
|
if isinstance(attr, tuple):
|
||||||
|
convenient, actual = attr
|
||||||
|
else:
|
||||||
|
convenient = actual = attr
|
||||||
|
if convenient == name:
|
||||||
|
print 'setting %s.%s.%s (via %s) to %s' % (
|
||||||
|
self.__class__.__name__, proxy, actual, convenient, repr(value))
|
||||||
|
return setattr(getattr(self, proxy), actual, value)
|
||||||
|
return super(ProxyModel, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
|
||||||
|
class PersonProxyModel(ProxyModel):
|
||||||
|
"""
|
||||||
|
Proxy model specific to :class:`rattail.django.rattail.models.Person`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta(ProxyModel.Meta):
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
_proxy_person = 'person'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._proxy_attribute_map[self._proxy_person] = [
|
||||||
|
'first_name',
|
||||||
|
'middle_name',
|
||||||
|
'last_name',
|
||||||
|
'driver_license_number',
|
||||||
|
'driver_license_state',
|
||||||
|
'address',
|
||||||
|
'update_address',
|
||||||
|
'set_preferred_address',
|
||||||
|
'phone',
|
||||||
|
'get_phone',
|
||||||
|
'update_phone',
|
||||||
|
'set_preferred_phone',
|
||||||
|
'email',
|
||||||
|
'update_email',
|
||||||
|
'set_preferred_email',
|
||||||
|
'make_employee',
|
||||||
|
'unmake_employee',
|
||||||
|
]
|
||||||
|
super(PersonProxyModel, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
getattr(self, self._proxy_person).save(**kwargs)
|
||||||
|
super(PersonProxyModel, self).save(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UUIDField(models.CharField):
|
class UUIDField(models.CharField):
|
||||||
"""
|
"""
|
||||||
"Custom" type for UUID fields. This is actually only necessary so that the
|
"Custom" type for UUID fields. This is actually only necessary so that the
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from edbob.db.extensions.contact.enum import EMAIL_PREFERENCE
|
from edbob.db.extensions.contact.enum import EMAIL_PREFERENCE
|
||||||
|
|
||||||
|
@ -38,17 +39,18 @@ from rattail.db.extension.enum import EMPLOYEE_STATUS
|
||||||
|
|
||||||
from rattail.django.rattail.models import Model, uuid_field
|
from rattail.django.rattail.models import Model, uuid_field
|
||||||
from rattail.django.rattail.models.contact import (
|
from rattail.django.rattail.models.contact import (
|
||||||
ContactInfoManager, PhoneNumber, EmailAddress)
|
ContactInfoManager, PhoneNumber, EmailAddress, PostalAddress,
|
||||||
|
PartyManager, Party, Person)
|
||||||
from rattail.django.util import enum_to_choices
|
from rattail.django.util import enum_to_choices
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['Store', 'StorePhoneNumber', 'StoreEmailAddress',
|
__all__ = ['Store', 'StorePhoneNumber', 'StoreEmailAddress', 'StorePostalAddress',
|
||||||
'Department', 'Subdepartment', 'Category', 'Brand',
|
'Department', 'Subdepartment', 'Category', 'Brand',
|
||||||
'Vendor', 'VendorPhoneNumber', 'VendorEmailAddress', 'VendorContact',
|
'Vendor', 'VendorPhoneNumber', 'VendorEmailAddress', 'VendorPostalAddress', 'VendorParty',
|
||||||
'Product', 'ProductPrice', 'ProductCost',
|
'Product', 'ProductPrice', 'ProductCost',
|
||||||
'Employee', 'EmployeePhoneNumber', 'EmployeeEmailAddress',
|
'Employee',
|
||||||
'Customer', 'CustomerPhoneNumber', 'CustomerEmailAddress', 'CustomerPerson',
|
'Customer', 'CustomerPhoneNumber', 'CustomerEmailAddress', 'CustomerPostalAddress',
|
||||||
'CustomerGroup', 'CustomerGroupAssignment',
|
'CustomerGroup', 'CustomerGroupAssignment', 'CustomerParty',
|
||||||
'LabelProfile']
|
'LabelProfile']
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,6 +122,12 @@ class StoreEmailAddress(EmailAddress, StoreContactInfo):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class StorePostalAddress(PostalAddress, StoreContactInfo):
|
||||||
|
"""
|
||||||
|
Represents a postal (mailing) address associated with a :class:`Store`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Department(Model):
|
class Department(Model):
|
||||||
"""
|
"""
|
||||||
Represents an organizational department.
|
Represents an organizational department.
|
||||||
|
@ -251,26 +259,27 @@ class VendorEmailAddress(EmailAddress, VendorContactInfo):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class VendorContact(Model):
|
class VendorPostalAddress(PostalAddress, VendorContactInfo):
|
||||||
"""
|
"""
|
||||||
Represents a point of contact (e.g. salesperson) for a vendor, from the
|
Represents a postal (mailing) address associated with a :class:`Vendor`.
|
||||||
retailer's perspective.
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class VendorParty(Party):
|
||||||
|
"""
|
||||||
|
Represents a "party" (e.g. sales contact) for a vendor, from the retailer's
|
||||||
|
perspective.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta(Model.Meta):
|
vendor = models.ForeignKey(Vendor, db_column='parent_uuid')
|
||||||
db_table = Model.prefix('vendor_contacts')
|
objects = PartyManager('Vendor')
|
||||||
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):
|
def __repr__(self):
|
||||||
return "<VendorContact: %s, %s>" % (self.vendor, self.person)
|
return "<VendorParty: %s, %s>" % (self.vendor, self.person)
|
||||||
|
|
||||||
def __unicode__(self):
|
def save(self, *args, **kwargs):
|
||||||
return unicode(self.person)
|
self.parent_type = 'Vendor'
|
||||||
|
super(VendorParty, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Product(Model):
|
class Product(Model):
|
||||||
|
@ -378,9 +387,9 @@ class Employee(Model):
|
||||||
EMPLOYEE_STATUS_CHOICES = enum_to_choices(EMPLOYEE_STATUS)
|
EMPLOYEE_STATUS_CHOICES = enum_to_choices(EMPLOYEE_STATUS)
|
||||||
|
|
||||||
uuid = uuid_field()
|
uuid = uuid_field()
|
||||||
id = models.IntegerField(blank=True, null=True, verbose_name="ID")
|
id = models.CharField(max_length=20, blank=True, null=True, verbose_name="ID")
|
||||||
person = models.ForeignKey('Person', db_column='person_uuid')
|
person = models.OneToOneField(Person, db_column='person_uuid', related_name='+')
|
||||||
status = models.IntegerField(choices=EMPLOYEE_STATUS_CHOICES)
|
status = models.IntegerField(choices=EMPLOYEE_STATUS_CHOICES, blank=True, null=True)
|
||||||
display_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Display Name")
|
display_name = models.CharField(max_length=100, blank=True, null=True, verbose_name="Display Name")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -402,34 +411,6 @@ class Employee(Model):
|
||||||
super(Employee, self).save(*args, **kwargs)
|
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):
|
class Customer(Model):
|
||||||
"""
|
"""
|
||||||
Represents a customer account. Customer accounts may consist of more than
|
Represents a customer account. Customer accounts may consist of more than
|
||||||
|
@ -453,6 +434,34 @@ class Customer(Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.name or '')
|
return unicode(self.name or '')
|
||||||
|
|
||||||
|
_primary_party = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def primary_party(self):
|
||||||
|
if self._primary_party is None:
|
||||||
|
qs = CustomerParty.objects
|
||||||
|
qs = qs.filter(customer=self)
|
||||||
|
qs = qs.filter(preference=1)
|
||||||
|
try:
|
||||||
|
self._primary_party = qs.get()
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
pass
|
||||||
|
return self._primary_party
|
||||||
|
|
||||||
|
def update_name(self):
|
||||||
|
orig_name = self.name
|
||||||
|
if self.primary_party:
|
||||||
|
person = self.primary_party.person
|
||||||
|
if not person.display_name:
|
||||||
|
person.update_display_name()
|
||||||
|
self.name = person.display_name
|
||||||
|
return self.name != orig_name
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.name:
|
||||||
|
self.update_name()
|
||||||
|
super(Customer, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class CustomerContactInfo(models.Model):
|
class CustomerContactInfo(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -482,26 +491,27 @@ class CustomerEmailAddress(EmailAddress, CustomerContactInfo):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CustomerPerson(Model):
|
class CustomerPostalAddress(PostalAddress, CustomerContactInfo):
|
||||||
"""
|
"""
|
||||||
Represents the association between a :class:`Person` and a customer account
|
Represents a postal (mailing) address associated with a :class:`Customer`.
|
||||||
(:class:`Customer`).
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerParty(Party):
|
||||||
|
"""
|
||||||
|
Represents a "party" (e.g. authorized shopper) for a customer, from the
|
||||||
|
retailer's perspective.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta(Model.Meta):
|
customer = models.ForeignKey(Customer, db_column='parent_uuid')
|
||||||
db_table = Model.prefix('customers_people')
|
objects = PartyManager('Customer')
|
||||||
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):
|
def __repr__(self):
|
||||||
return "<CustomerPerson: %s>" % self.person
|
return "<CustomerParty: %s, %s>" % (self.customer, self.person)
|
||||||
|
|
||||||
def __unicode__(self):
|
def save(self, *args, **kwargs):
|
||||||
return unicode(self.person or '')
|
self.parent_type = 'Customer'
|
||||||
|
super(CustomerParty, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class CustomerGroup(Model):
|
class CustomerGroup(Model):
|
||||||
|
|
42
rattail/django/rattail/urls.py
Normal file
42
rattail/django/rattail/urls.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.django.rattail.urls`` -- URL Configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
from rattail.django.rattail import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
|
||||||
|
url(r'^zipcode/$',
|
||||||
|
views.get_zipcode_data,
|
||||||
|
name='rattail_zipcode'),
|
||||||
|
|
||||||
|
)
|
59
rattail/django/rattail/views.py
Normal file
59
rattail/django/rattail/views.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#!/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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
``rattail.django.rattail.views`` -- Views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.utils import simplejson as json
|
||||||
|
|
||||||
|
from pyzipcode import ZipCodeDatabase
|
||||||
|
|
||||||
|
|
||||||
|
zcdb = ZipCodeDatabase()
|
||||||
|
|
||||||
|
|
||||||
|
def get_zipcode_data(request):
|
||||||
|
"""
|
||||||
|
Returns everything knowable about a given zipcode, as a JSON string.
|
||||||
|
Returns an empty string if the zipcode is not found in the database.
|
||||||
|
"""
|
||||||
|
|
||||||
|
zipcode = request.GET.get('zipcode')
|
||||||
|
zipcode = zcdb.get(zipcode)
|
||||||
|
if not zipcode:
|
||||||
|
return HttpResponse('')
|
||||||
|
|
||||||
|
zipcode = zipcode[0]
|
||||||
|
data = {
|
||||||
|
'city': zipcode.city,
|
||||||
|
'state': zipcode.state,
|
||||||
|
'zip': zipcode.zip,
|
||||||
|
'latitude': zipcode.latitude,
|
||||||
|
'longitude': zipcode.longitude,
|
||||||
|
'timezone': zipcode.timezone,
|
||||||
|
'dst': zipcode.dst,
|
||||||
|
}
|
||||||
|
return HttpResponse(json.dumps(data), content_type='application/json')
|
Loading…
Reference in a new issue