mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 12:45:42 +00:00 
			
		
		
		
	Adds "contact" to ReturnOrder
- Implement check to ensure that the selected "contact" matches the selected "company"
This commit is contained in:
		| @@ -235,6 +235,11 @@ class Contact(models.Model): | ||||
|         role: position in company | ||||
|     """ | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the Contcat model""" | ||||
|         return reverse('api-contact-list') | ||||
|  | ||||
|     company = models.ForeignKey(Company, related_name='contacts', | ||||
|                                 on_delete=models.CASCADE) | ||||
|  | ||||
|   | ||||
| @@ -170,6 +170,18 @@ class Order(MetadataMixin, ReferenceIndexingMixin): | ||||
|  | ||||
|         super().save(*args, **kwargs) | ||||
|  | ||||
|     def clean(self): | ||||
|         """Custom clean method for the generic order class""" | ||||
|  | ||||
|         super().clean() | ||||
|  | ||||
|         # Check that the referenced 'contact' matches the correct 'company' | ||||
|         if self.company and self.contact: | ||||
|             if self.contact.company != self.company: | ||||
|                 raise ValidationError({ | ||||
|                     "contact": _("Contact does not match selected company") | ||||
|                 }) | ||||
|  | ||||
|     description = models.CharField(max_length=250, verbose_name=_('Description'), help_text=_('Order description')) | ||||
|  | ||||
|     link = InvenTreeURLField(blank=True, verbose_name=_('Link'), help_text=_('Link to external page')) | ||||
| @@ -305,6 +317,11 @@ class PurchaseOrder(TotalPriceMixin, Order): | ||||
|         help_text=_('Company from which the items are being ordered') | ||||
|     ) | ||||
|  | ||||
|     @property | ||||
|     def company(self): | ||||
|         """Accessor helper for Order base class""" | ||||
|         return self.suplier | ||||
|  | ||||
|     supplier_reference = models.CharField(max_length=64, blank=True, verbose_name=_('Supplier Reference'), help_text=_("Supplier order reference code")) | ||||
|  | ||||
|     received_by = models.ForeignKey( | ||||
| @@ -711,6 +728,11 @@ class SalesOrder(TotalPriceMixin, Order): | ||||
|         help_text=_("Company to which the items are being sold"), | ||||
|     ) | ||||
|  | ||||
|     @property | ||||
|     def company(self): | ||||
|         """Accessor helper for Order base""" | ||||
|         return self.customer | ||||
|  | ||||
|     status = models.PositiveIntegerField( | ||||
|         default=SalesOrderStatus.PENDING, | ||||
|         choices=SalesOrderStatus.items(), | ||||
| @@ -1626,6 +1648,11 @@ class ReturnOrder(Order): | ||||
|         help_text=_("Company from which items are being returned"), | ||||
|     ) | ||||
|  | ||||
|     @property | ||||
|     def company(self): | ||||
|         """Accessor helper for Order base class""" | ||||
|         return self.customer | ||||
|  | ||||
|     status = models.PositiveIntegerField( | ||||
|         default=ReturnOrderStatus.PENDING, | ||||
|         choices=ReturnOrderStatus.items(), | ||||
|   | ||||
| @@ -17,7 +17,8 @@ import order.models | ||||
| import part.filters | ||||
| import stock.models | ||||
| import stock.serializers | ||||
| from company.serializers import CompanyBriefSerializer, SupplierPartSerializer | ||||
| from company.serializers import (CompanyBriefSerializer, ContactSerializer, | ||||
|                                  SupplierPartSerializer) | ||||
| from InvenTree.helpers import extract_serial_numbers, normalize, str2bool | ||||
| from InvenTree.serializers import (InvenTreeAttachmentSerializer, | ||||
|                                    InvenTreeCurrencySerializer, | ||||
| @@ -1411,6 +1412,8 @@ class ReturnOrderSerializer(InvenTreeModelSerializer): | ||||
|         fields = [ | ||||
|             'pk', | ||||
|             'creation_date', | ||||
|             'contact', | ||||
|             'contact_detail', | ||||
|             'customer', | ||||
|             'customer_detail', | ||||
|             'customer_reference', | ||||
| @@ -1446,6 +1449,8 @@ class ReturnOrderSerializer(InvenTreeModelSerializer): | ||||
|         # TODO | ||||
|         return queryset | ||||
|  | ||||
|     contact_detail = ContactSerializer(source='contact', many=False, read_only=True) | ||||
|  | ||||
|     customer_detail = CompanyBriefSerializer(source='customer', many=False, read_only=True) | ||||
|  | ||||
|     status_text = serializers.CharField(source='get_status_display', read_only=True) | ||||
|   | ||||
| @@ -204,12 +204,13 @@ src="{% static 'img/blank_image.png' %}" | ||||
| {% block js_ready %} | ||||
| {{ block.super }} | ||||
|  | ||||
| {% if roles.sales_order.change %} | ||||
| $("#edit-order").click(function() { | ||||
|  | ||||
|     editSalesOrder({{ order.pk }}, { | ||||
|         reload: true, | ||||
|     }); | ||||
| }); | ||||
| {% endif %} | ||||
|  | ||||
| $("#complete-order-shipments").click(function() { | ||||
|  | ||||
|   | ||||
| @@ -2044,6 +2044,9 @@ function renderModelData(name, model, data, parameters, options) { | ||||
|     case 'company': | ||||
|         renderer = renderCompany; | ||||
|         break; | ||||
|     case 'contact': | ||||
|         renderer = renderContact; | ||||
|         break; | ||||
|     case 'stockitem': | ||||
|         renderer = renderStockItem; | ||||
|         break; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| /* exported | ||||
|     renderBuild, | ||||
|     renderCompany, | ||||
|     renderContact, | ||||
|     renderGroup, | ||||
|     renderManufacturerPart, | ||||
|     renderOwner, | ||||
| @@ -67,7 +68,7 @@ function renderId(title, pk, parameters={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderCompany(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = select2Thumbnail(data.image); | ||||
|     let html = select2Thumbnail(data.image); | ||||
|  | ||||
|     html += `<span><b>${data.name}</b></span> - <i>${trim(data.description)}</i>`; | ||||
|  | ||||
| @@ -77,6 +78,21 @@ function renderCompany(name, data, parameters={}, options={}) { | ||||
| } | ||||
|  | ||||
|  | ||||
| // Renderer for the "Contact" model | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderContact(name, data, parameters={}, options={}) { | ||||
|     let html = `<span><b>${data.name}</b>`; | ||||
|  | ||||
|     if (data.email) { | ||||
|         html += `- <i>${data.email}</i>`; | ||||
|  | ||||
|         html += renderId('{% trans "Contact ID" %}', data.pk, parameters); | ||||
|     } | ||||
|  | ||||
|     return html; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Renderer for "StockItem" model | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderStockItem(name, data, parameters={}, options={}) { | ||||
| @@ -138,7 +154,7 @@ function renderStockItem(name, data, parameters={}, options={}) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     var html = ` | ||||
|     let html = ` | ||||
|     <span> | ||||
|         ${part_detail} | ||||
|         ${stock_detail} | ||||
| @@ -157,7 +173,7 @@ function renderStockLocation(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var level = '- '.repeat(data.level); | ||||
|  | ||||
|     var html = `<span>${level}${data.pathstring}</span>`; | ||||
|     let html = `<span>${level}${data.pathstring}</span>`; | ||||
|  | ||||
|     var render_description = true; | ||||
|  | ||||
| @@ -183,7 +199,7 @@ function renderBuild(name, data, parameters={}, options={}) { | ||||
|         image = data.part_detail.thumbnail; | ||||
|     } | ||||
|  | ||||
|     var html = select2Thumbnail(image); | ||||
|     let html = select2Thumbnail(image); | ||||
|  | ||||
|     html += `<span><b>${data.reference}</b> - ${data.quantity} x ${data.part_detail.full_name}</span>`; | ||||
|  | ||||
| @@ -197,7 +213,7 @@ function renderBuild(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderPart(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = select2Thumbnail(data.image); | ||||
|     let html = select2Thumbnail(data.image); | ||||
|  | ||||
|     html += ` <span>${data.full_name || data.name}</span>`; | ||||
|  | ||||
| @@ -234,7 +250,7 @@ function renderPart(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderGroup(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = `<span>${data.name}</span>`; | ||||
|     let html = `<span>${data.name}</span>`; | ||||
|  | ||||
|     return html; | ||||
|  | ||||
| @@ -244,7 +260,7 @@ function renderGroup(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderUser(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = `<span>${data.username}</span>`; | ||||
|     let html = `<span>${data.username}</span>`; | ||||
|  | ||||
|     if (data.first_name && data.last_name) { | ||||
|         html += ` - <i>${data.first_name} ${data.last_name}</i>`; | ||||
| @@ -258,7 +274,7 @@ function renderUser(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderOwner(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = `<span>${data.name}</span>`; | ||||
|     let html = `<span>${data.name}</span>`; | ||||
|  | ||||
|     switch (data.label) { | ||||
|     case 'user': | ||||
| @@ -279,7 +295,7 @@ function renderOwner(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderPurchaseOrder(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = ''; | ||||
|     let html = ''; | ||||
|  | ||||
|     if (data.supplier_detail) { | ||||
|         thumbnail = data.supplier_detail.thumbnail || data.supplier_detail.image; | ||||
| @@ -309,7 +325,7 @@ function renderPurchaseOrder(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderSalesOrder(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = `<span>${data.reference}</span>`; | ||||
|     let html = `<span>${data.reference}</span>`; | ||||
|  | ||||
|     var thumbnail = null; | ||||
|  | ||||
| @@ -334,7 +350,7 @@ function renderSalesOrder(name, data, parameters={}, options={}) { | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function renderSalesOrderShipment(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var html = ` | ||||
|     let html = ` | ||||
|     <span>${data.order_detail.reference} - {% trans "Shipment" %} ${data.reference}</span> | ||||
|     <span class='float-right'> | ||||
|         <small>{% trans "Shipment ID" %}: ${data.pk}</small> | ||||
| @@ -353,7 +369,7 @@ function renderPartCategory(name, data, parameters={}, options={}) { | ||||
|  | ||||
|     var level = '- '.repeat(data.level); | ||||
|  | ||||
|     var html = `<span>${level}${data.pathstring}</span>`; | ||||
|     let html = `<span>${level}${data.pathstring}</span>`; | ||||
|  | ||||
|     if (data.description) { | ||||
|         html += ` - <i>${trim(data.description)}</i>`; | ||||
| @@ -373,7 +389,7 @@ function renderPartParameterTemplate(name, data, parameters={}, options={}) { | ||||
|         units = ` [${data.units}]`; | ||||
|     } | ||||
|  | ||||
|     var html = `<span>${data.name}${units}</span>`; | ||||
|     let html = `<span>${data.name}${units}</span>`; | ||||
|  | ||||
|     return html; | ||||
| } | ||||
| @@ -394,7 +410,7 @@ function renderManufacturerPart(name, data, parameters={}, options={}) { | ||||
|         part_image = data.part_detail.thumbnail || data.part_detail.image; | ||||
|     } | ||||
|  | ||||
|     var html = ''; | ||||
|     let html = ''; | ||||
|  | ||||
|     html += select2Thumbnail(manufacturer_image); | ||||
|     html += select2Thumbnail(part_image); | ||||
| @@ -423,7 +439,7 @@ function renderSupplierPart(name, data, parameters={}, options={}) { | ||||
|         part_image = data.part_detail.thumbnail || data.part_detail.image; | ||||
|     } | ||||
|  | ||||
|     var html = ''; | ||||
|     let html = ''; | ||||
|  | ||||
|     html += select2Thumbnail(supplier_image); | ||||
|  | ||||
|   | ||||
| @@ -50,6 +50,9 @@ function returnOrderFields(options={}) { | ||||
|         link: { | ||||
|             icon: 'fa-link', | ||||
|         }, | ||||
|         contact: { | ||||
|             icon: 'fa-user', | ||||
|         }, | ||||
|         responsible: { | ||||
|             icon: 'fa-user', | ||||
|         } | ||||
|   | ||||
| @@ -136,6 +136,7 @@ class RuleSet(models.Model): | ||||
|         'purchase_order': [ | ||||
|             'company_company', | ||||
|             'company_companyattachment', | ||||
|             'company_contact', | ||||
|             'company_manufacturerpart', | ||||
|             'company_manufacturerpartparameter', | ||||
|             'company_supplierpart', | ||||
| @@ -149,6 +150,7 @@ class RuleSet(models.Model): | ||||
|         'sales_order': [ | ||||
|             'company_company', | ||||
|             'company_companyattachment', | ||||
|             'company_contact', | ||||
|             'order_salesorder', | ||||
|             'order_salesorderallocation', | ||||
|             'order_salesorderattachment', | ||||
| @@ -160,6 +162,7 @@ class RuleSet(models.Model): | ||||
|         'return_order': [ | ||||
|             'company_company', | ||||
|             'company_companyattachment', | ||||
|             'company_contact', | ||||
|             'order_returnorder', | ||||
|             'order_returnorderlineitem', | ||||
|             'order_returnorderextraline', | ||||
| @@ -181,7 +184,6 @@ class RuleSet(models.Model): | ||||
|         'common_webhookmessage', | ||||
|         'common_notificationentry', | ||||
|         'common_notificationmessage', | ||||
|         'company_contact', | ||||
|         'users_owner', | ||||
|  | ||||
|         # Third-party tables | ||||
|   | ||||
		Reference in New Issue
	
	Block a user