Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
chris
repanier
Commits
070c7057
Commit
070c7057
authored
Jun 26, 2017
by
Patrick
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce contracts which are at first like boxes
parent
9ebbb534
Changes
33
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1531 additions
and
23747 deletions
+1531
-23747
repanier/admin/__init__.py
repanier/admin/__init__.py
+3
-0
repanier/admin/contract.py
repanier/admin/contract.py
+309
-0
repanier/admin/producer.py
repanier/admin/producer.py
+9
-3
repanier/const.py
repanier/const.py
+3
-0
repanier/models/__init__.py
repanier/models/__init__.py
+2
-0
repanier/models/box.py
repanier/models/box.py
+0
-1
repanier/models/contract.py
repanier/models/contract.py
+123
-0
repanier/models/item.py
repanier/models/item.py
+4
-2
repanier/models/producer.py
repanier/models/producer.py
+14
-0
repanier/static/bootstrap/css/bees-coop II/bootstrap.css
repanier/static/bootstrap/css/bees-coop II/bootstrap.css
+0
-6289
repanier/static/bootstrap/css/bees-coop II/bootstrap.css.gz
repanier/static/bootstrap/css/bees-coop II/bootstrap.css.gz
+0
-0
repanier/static/bootstrap/css/bees-coop II/bootswatch.less
repanier/static/bootstrap/css/bees-coop II/bootswatch.less
+0
-189
repanier/static/bootstrap/css/bees-coop II/custom.css
repanier/static/bootstrap/css/bees-coop II/custom.css
+0
-49
repanier/static/bootstrap/css/bees-coop II/favicon.ico
repanier/static/bootstrap/css/bees-coop II/favicon.ico
+0
-0
repanier/static/bootstrap/css/bees-coop II/variableswatch.css
...nier/static/bootstrap/css/bees-coop II/variableswatch.css
+0
-0
repanier/static/bootstrap/css/bees-coop II/variableswatch.less
...ier/static/bootstrap/css/bees-coop II/variableswatch.less
+0
-846
repanier/static/bootstrap/css/bees-coop/bootstrap.css
repanier/static/bootstrap/css/bees-coop/bootstrap.css
+0
-6289
repanier/static/bootstrap/css/bees-coop/bootswatch.less
repanier/static/bootstrap/css/bees-coop/bootswatch.less
+0
-189
repanier/static/bootstrap/css/bees-coop/custom.css
repanier/static/bootstrap/css/bees-coop/custom.css
+0
-49
repanier/static/bootstrap/css/bees-coop/variableswatch.css
repanier/static/bootstrap/css/bees-coop/variableswatch.css
+0
-0
repanier/static/bootstrap/css/bees-coop/variableswatch.less
repanier/static/bootstrap/css/bees-coop/variableswatch.less
+0
-846
repanier/static/bootstrap/css/bootstrap-theme.css
repanier/static/bootstrap/css/bootstrap-theme.css
+0
-347
repanier/static/bootstrap/css/bootstrap.css
repanier/static/bootstrap/css/bootstrap.css
+0
-6766
repanier/static/bootstrap/css/bootstrap.css.gz
repanier/static/bootstrap/css/bootstrap.css.gz
+0
-0
repanier/static/bootstrap/css/bootstrap.less
repanier/static/bootstrap/css/bootstrap.less
+0
-59
repanier/static/bootstrap/css/variableswatch.less
repanier/static/bootstrap/css/variableswatch.less
+0
-869
repanier/static/bootstrap/fonts/glyphicons-halflings-regular.eot
...r/static/bootstrap/fonts/glyphicons-halflings-regular.eot
+0
-0
repanier/static/bootstrap/fonts/glyphicons-halflings-regular.svg
...r/static/bootstrap/fonts/glyphicons-halflings-regular.svg
+272
-213
repanier/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
...r/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
+0
-0
repanier/static/bootstrap/fonts/glyphicons-halflings-regular.woff
.../static/bootstrap/fonts/glyphicons-halflings-regular.woff
+0
-0
repanier/static/bootstrap/js/bootstrap.js
repanier/static/bootstrap/js/bootstrap.js
+725
-725
repanier/task/task_contract.py
repanier/task/task_contract.py
+56
-0
repanier/tools.py
repanier/tools.py
+11
-16
No files found.
repanier/admin/__init__.py
View file @
070c7057
...
...
@@ -43,6 +43,9 @@ admin.site.register(Product, ProductAdmin)
from
repanier.models.box
import
Box
from
repanier.admin.box
import
BoxAdmin
admin
.
site
.
register
(
Box
,
BoxAdmin
)
from
repanier.models.contract
import
Contract
from
repanier.admin.contract
import
ContractAdmin
admin
.
site
.
register
(
Contract
,
ContractAdmin
)
from
repanier.models.staff
import
Staff
from
repanier.admin.staff
import
StaffWithUserDataAdmin
admin
.
site
.
register
(
Staff
,
StaffWithUserDataAdmin
)
repanier/admin/contract.py
0 → 100644
View file @
070c7057
# -*- coding: utf-8
from
__future__
import
unicode_literals
from
os
import
sep
as
os_sep
from
django
import
forms
from
django.conf
import
settings
from
django.contrib
import
admin
from
django.contrib
import
messages
from
django.contrib.admin
import
TabularInline
from
django.forms
import
ModelForm
,
BaseInlineFormSet
from
django.forms.formsets
import
DELETION_FIELD_NAME
from
django.shortcuts
import
render
from
django.utils
import
translation
from
django.utils.translation
import
ugettext_lazy
as
_
from
easy_select2
import
Select2
from
parler.admin
import
TranslatableAdmin
from
parler.forms
import
TranslatableModelForm
from
repanier.admin.fkey_choice_cache_mixin
import
ForeignKeyCacheMixin
from
repanier.const
import
DECIMAL_ZERO
,
ORDER_GROUP
,
INVOICE_GROUP
,
\
COORDINATION_GROUP
,
PERMANENCE_PLANNED
,
PERMANENCE_CLOSED
from
repanier.models.contract
import
ContractContent
,
Contract
from
repanier.models.product
import
Product
from
repanier.models.offeritem
import
OfferItemWoReceiver
from
repanier.task
import
task_contract
from
repanier.tools
import
update_offer_item
try
:
from
urllib.parse
import
parse_qsl
except
ImportError
:
from
urlparse
import
parse_qsl
class
ContractContentInlineFormSet
(
BaseInlineFormSet
):
def
clean
(
self
):
products
=
set
()
for
form
in
self
.
forms
:
if
form
.
cleaned_data
and
not
form
.
cleaned_data
.
get
(
'DELETE'
):
# This is not an empty form or a "to be deleted" form
product
=
form
.
cleaned_data
.
get
(
'product'
,
None
)
if
product
is
not
None
:
if
product
in
products
:
raise
forms
.
ValidationError
(
_
(
'Duplicate product are not allowed.'
))
else
:
products
.
add
(
product
)
def
get_queryset
(
self
):
return
self
.
queryset
.
filter
(
product__translations__language_code
=
translation
.
get_language
()
).
order_by
(
"product__producer__short_profile_name"
,
"product__translations__long_name"
,
"product__order_average_weight"
,
)
class
ContractContentInlineForm
(
ModelForm
):
is_into_offer
=
forms
.
BooleanField
(
label
=
_
(
"is_into_offer"
),
required
=
False
,
initial
=
True
)
stock
=
forms
.
DecimalField
(
label
=
_
(
"Current stock"
),
max_digits
=
9
,
decimal_places
=
3
,
required
=
False
,
initial
=
DECIMAL_ZERO
)
limit_order_quantity_to_stock
=
forms
.
BooleanField
(
label
=
_
(
"limit maximum order qty of the group to stock qty"
),
required
=
False
,
initial
=
True
)
previous_product
=
forms
.
ModelChoiceField
(
Product
.
objects
.
none
(),
required
=
False
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
ContractContentInlineForm
,
self
).
__init__
(
*
args
,
**
kwargs
)
self
.
fields
[
"product"
].
widget
.
can_add_related
=
False
self
.
fields
[
"product"
].
widget
.
can_delete_related
=
False
if
self
.
instance
.
id
is
not
None
:
self
.
fields
[
"is_into_offer"
].
initial
=
self
.
instance
.
product
.
is_into_offer
self
.
fields
[
"stock"
].
initial
=
self
.
instance
.
product
.
stock
self
.
fields
[
"limit_order_quantity_to_stock"
].
initial
=
self
.
instance
.
product
.
limit_order_quantity_to_stock
self
.
fields
[
"previous_product"
].
initial
=
self
.
instance
.
product
self
.
fields
[
"is_into_offer"
].
disabled
=
True
self
.
fields
[
"stock"
].
disabled
=
True
self
.
fields
[
"limit_order_quantity_to_stock"
].
disabled
=
True
class
Meta
:
widgets
=
{
'product'
:
Select2
(
select2attrs
=
{
'width'
:
'450px'
})
}
class
ContractContentInline
(
ForeignKeyCacheMixin
,
TabularInline
):
form
=
ContractContentInlineForm
formset
=
ContractContentInlineFormSet
model
=
ContractContent
ordering
=
(
"product"
,)
fields
=
[
'product'
,
'is_into_offer'
,
'content_quantity'
,
'stock'
,
'limit_order_quantity_to_stock'
,
'get_calculated_customer_content_price'
]
extra
=
0
fk_name
=
'contract'
# The stock and limit_order_quantity_to_stock are read only to have only one place to update it : the product.
readonly_fields
=
[
'get_calculated_customer_content_price'
]
has_add_or_delete_permission
=
None
def
has_delete_permission
(
self
,
request
,
obj
=
None
):
if
self
.
has_add_or_delete_permission
is
None
:
try
:
parent_object
=
Contract
.
objects
.
filter
(
id
=
request
.
resolver_match
.
args
[
0
]
).
only
(
"id"
).
order_by
(
'?'
).
first
()
if
parent_object
is
not
None
and
OfferItemWoReceiver
.
objects
.
filter
(
product
=
parent_object
.
id
,
permanence__status__gt
=
PERMANENCE_PLANNED
,
permanence__status__lt
=
PERMANENCE_CLOSED
).
order_by
(
'?'
).
exists
():
self
.
has_add_or_delete_permission
=
False
else
:
self
.
has_add_or_delete_permission
=
True
except
:
self
.
has_add_or_delete_permission
=
True
return
self
.
has_add_or_delete_permission
def
has_add_permission
(
self
,
request
):
return
self
.
has_delete_permission
(
request
)
def
formfield_for_foreignkey
(
self
,
db_field
,
request
,
**
kwargs
):
if
db_field
.
name
==
"product"
:
kwargs
[
"queryset"
]
=
Product
.
objects
.
filter
(
is_active
=
True
,
# A contract may not include another contract
is_contract
=
False
,
# We can't make any composition with producer preparing baskets on basis of our order.
producer__invoice_by_basket
=
False
,
translations__language_code
=
translation
.
get_language
()
).
order_by
(
"producer__short_profile_name"
,
"translations__long_name"
,
"order_average_weight"
,
)
return
super
(
ContractContentInline
,
self
).
formfield_for_foreignkey
(
db_field
,
request
,
**
kwargs
)
class
ContractForm
(
TranslatableModelForm
):
calculated_stock
=
forms
.
DecimalField
(
label
=
_
(
"Calculated current stock"
),
max_digits
=
9
,
decimal_places
=
3
,
required
=
False
,
initial
=
DECIMAL_ZERO
)
calculated_customer_contract_price
=
forms
.
DecimalField
(
label
=
_
(
"calculated customer contract price"
),
max_digits
=
8
,
decimal_places
=
2
,
required
=
False
,
initial
=
DECIMAL_ZERO
)
calculated_contract_deposit
=
forms
.
DecimalField
(
label
=
_
(
"calculated contract deposit"
),
max_digits
=
8
,
decimal_places
=
2
,
required
=
False
,
initial
=
DECIMAL_ZERO
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
ContractForm
,
self
).
__init__
(
*
args
,
**
kwargs
)
contract
=
self
.
instance
if
contract
.
id
is
not
None
:
contract_price
,
contract_deposit
=
contract
.
get_calculated_price
()
self
.
fields
[
"calculated_stock"
].
initial
=
contract
.
get_calculated_stock
()
self
.
fields
[
"calculated_customer_contract_price"
].
initial
=
contract_price
self
.
fields
[
"calculated_contract_deposit"
].
initial
=
contract_deposit
self
.
fields
[
"calculated_customer_contract_price"
].
disabled
=
True
self
.
fields
[
"calculated_stock"
].
disabled
=
True
self
.
fields
[
"calculated_contract_deposit"
].
disabled
=
True
class
ContractAdmin
(
TranslatableAdmin
):
form
=
ContractForm
model
=
Contract
list_display
=
(
'is_into_offer'
,
'get_long_name'
,
'language_column'
,
)
list_display_links
=
(
'get_long_name'
,)
list_per_page
=
16
list_max_show_all
=
16
inlines
=
(
ContractContentInline
,)
filter_horizontal
=
(
'production_mode'
,)
ordering
=
(
'customer_unit_price'
,
'unit_deposit'
,
'translations__long_name'
,)
search_fields
=
(
'translations__long_name'
,)
list_filter
=
(
'is_active'
,
'is_into_offer'
)
actions
=
[
'flip_flop_select_for_offer_status'
,
'duplicate_contract'
]
def
has_delete_permission
(
self
,
request
,
contract
=
None
):
if
request
.
user
.
groups
.
filter
(
name__in
=
[
ORDER_GROUP
,
INVOICE_GROUP
,
COORDINATION_GROUP
]).
exists
()
or
request
.
user
.
is_superuser
:
return
True
return
False
def
has_add_permission
(
self
,
request
):
return
self
.
has_delete_permission
(
request
)
def
has_change_permission
(
self
,
request
,
contract
=
None
):
return
self
.
has_delete_permission
(
request
,
contract
)
def
get_list_display
(
self
,
request
):
self
.
list_editable
=
(
'stock'
,)
if
settings
.
DJANGO_SETTINGS_MULTIPLE_LANGUAGE
:
return
(
'get_is_into_offer'
,
'get_long_name'
,
'language_column'
,
'stock'
)
else
:
return
(
'get_is_into_offer'
,
'get_long_name'
,
'stock'
)
def
flip_flop_select_for_offer_status
(
self
,
request
,
queryset
):
task_contract
.
flip_flop_is_into_offer
(
queryset
)
flip_flop_select_for_offer_status
.
short_description
=
_
(
'flip_flop_select_for_offer_status for offer'
)
def
duplicate_contract
(
self
,
request
,
queryset
):
if
'cancel'
in
request
.
POST
:
user_message
=
_
(
"Action canceled by the user."
)
user_message_level
=
messages
.
INFO
self
.
message_user
(
request
,
user_message
,
user_message_level
)
return
contract
=
queryset
.
first
()
if
contract
is
None
:
user_message
=
_
(
"Action canceled by the system."
)
user_message_level
=
messages
.
ERROR
self
.
message_user
(
request
,
user_message
,
user_message_level
)
return
if
'apply'
in
request
.
POST
:
user_message
,
user_message_level
=
task_contract
.
admin_duplicate
(
queryset
)
self
.
message_user
(
request
,
user_message
,
user_message_level
)
return
return
render
(
request
,
'repanier/confirm_admin_duplicate_contract.html'
,
{
'sub_title'
:
_
(
"Please, confirm the action : duplicate contract"
),
'action_checkcontract_name'
:
admin
.
ACTION_CHECKBOX_NAME
,
'action'
:
'duplicate_contract'
,
'product'
:
contract
,
})
duplicate_contract
.
short_description
=
_
(
'duplicate contract'
)
def
get_fieldsets
(
self
,
request
,
contract
=
None
):
fields_basic
=
[
(
'long_name'
,
'picture2'
),
(
'calculated_stock'
,
'calculated_customer_contract_price'
,
'calculated_contract_deposit'
),
(
'stock'
,
'customer_unit_price'
,
'unit_deposit'
),
]
fields_advanced_descriptions
=
[
'placement'
,
'offer_description'
,
'production_mode'
,
]
fields_advanced_options
=
[
(
'reference'
,
'vat_level'
),
(
'is_into_offer'
,
'is_active'
,
'is_updated_on'
)
]
fieldsets
=
(
(
None
,
{
'fields'
:
fields_basic
}),
(
_
(
'Advanced descriptions'
),
{
'classes'
:
(
'collapse'
,),
'fields'
:
fields_advanced_descriptions
}),
(
_
(
'Advanced options'
),
{
'classes'
:
(
'collapse'
,),
'fields'
:
fields_advanced_options
})
)
return
fieldsets
def
get_readonly_fields
(
self
,
request
,
customer
=
None
):
return
[
'is_updated_on'
]
def
get_form
(
self
,
request
,
contract
=
None
,
**
kwargs
):
form
=
super
(
ContractAdmin
,
self
).
get_form
(
request
,
contract
,
**
kwargs
)
picture_field
=
form
.
base_fields
[
"picture2"
]
if
hasattr
(
picture_field
.
widget
,
'upload_to'
):
picture_field
.
widget
.
upload_to
=
"%s%s%s"
%
(
"product"
,
os_sep
,
"contract"
)
return
form
def
get_queryset
(
self
,
request
):
qs
=
super
(
ContractAdmin
,
self
).
get_queryset
(
request
)
qs
=
qs
.
filter
(
is_contract
=
True
,
translations__language_code
=
translation
.
get_language
()
)
return
qs
def
save_model
(
self
,
request
,
contract
,
form
,
change
):
super
(
ContractAdmin
,
self
).
save_model
(
request
,
contract
,
form
,
change
)
update_offer_item
(
contract
)
def
save_related
(
self
,
request
,
form
,
formsets
,
change
):
for
formset
in
formsets
:
# option.py -> construct_change_message doesn't test the presence of those array not created at form initialisation...
if
not
hasattr
(
formset
,
'new_objects'
):
formset
.
new_objects
=
[]
if
not
hasattr
(
formset
,
'changed_objects'
):
formset
.
changed_objects
=
[]
if
not
hasattr
(
formset
,
'deleted_objects'
):
formset
.
deleted_objects
=
[]
contract
=
form
.
instance
try
:
formset
=
formsets
[
0
]
for
contract_content_form
in
formset
:
contract_content
=
contract_content_form
.
instance
previous_product
=
contract_content_form
.
fields
[
'previous_product'
].
initial
if
previous_product
is
not
None
and
previous_product
!=
contract_content
.
product
:
# Delete the contract_content because the product has changed
contract_content_form
.
instance
.
delete
()
if
contract_content
.
product
is
not
None
:
if
contract_content
.
id
is
None
:
contract_content
.
contract_id
=
contract
.
id
if
contract_content_form
.
cleaned_data
.
get
(
DELETION_FIELD_NAME
,
False
):
contract_content_form
.
instance
.
delete
()
elif
contract_content_form
.
has_changed
():
contract_content_form
.
instance
.
save
()
except
IndexError
:
# No formset present in list admin, but well in detail admin
pass
repanier/admin/producer.py
View file @
070c7057
...
...
@@ -322,10 +322,16 @@ class ProducerAdmin(ImportExportMixin, admin.ModelAdmin):
return
actions
def
get_list_display
(
self
,
request
):
if
repanier
.
apps
.
REPANIER_SETTINGS_INVOICE
:
return
(
'__str__'
,
'get_products'
,
'get_balance'
,
'phone1'
,
'email'
)
if
settings
.
DJANGO_SETTINGS_IS_MINIMALIST
:
if
repanier
.
apps
.
REPANIER_SETTINGS_INVOICE
:
return
(
'__str__'
,
'get_products'
,
'get_balance'
,
'phone1'
,
'email'
)
else
:
return
(
'__str__'
,
'get_products'
,
'phone1'
,
'email'
)
else
:
return
(
'__str__'
,
'get_products'
,
'phone1'
,
'email'
)
if
repanier
.
apps
.
REPANIER_SETTINGS_INVOICE
:
return
(
'__str__'
,
'get_products'
,
'get_contracts'
,
'get_balance'
,
'phone1'
,
'email'
)
else
:
return
(
'__str__'
,
'get_products'
,
'get_contracts'
,
'phone1'
,
'email'
)
def
get_fieldsets
(
self
,
request
,
producer
=
None
):
fields_basic
=
[
...
...
repanier/const.py
View file @
070c7057
...
...
@@ -288,6 +288,9 @@ BOX_UNICODE = "📦" # http://unicode-table.com/fr/1F6CD/
LOCK_UNICODE
=
"✓🔐"
VALID_UNICODE
=
"✓"
BANK_NOTE_UNICODE
=
"💶"
CONTRACT_VALUE_STR
=
"-1"
CONTRACT_VALUE_INT
=
-
1
CONTRACT_UNICODE
=
"🤝"
LUT_CONFIRM
=
(
(
True
,
LOCK_UNICODE
),
(
False
,
EMPTY_STRING
)
...
...
repanier/models/__init__.py
View file @
070c7057
...
...
@@ -15,8 +15,10 @@ from .purchase import Purchase
from
.staff
import
Staff
# after Producer and Product
from
.box
import
BoxContent
from
.contract
import
ContractContent
# proxies
from
.box
import
Box
from
.
contract
import
Contract
from
.invoice
import
CustomerSend
from
.offeritem
import
OfferItemSend
,
OfferItemClosed
,
OfferItemWoReceiver
from
.permanence
import
PermanenceInPreparation
,
PermanenceDone
repanier/models/box.py
View file @
070c7057
...
...
@@ -103,7 +103,6 @@ class BoxContent(models.Model):
verbose_name_plural
=
_
(
"boxes content"
)
unique_together
=
(
"box"
,
"product"
,)
index_together
=
[
# ["box", "product"],
[
"product"
,
"box"
],
]
...
...
repanier/models/contract.py
0 → 100644
View file @
070c7057
# -*- coding: utf-8
from
__future__
import
unicode_literals
from
django.core.validators
import
MinValueValidator
from
django.db
import
models
from
django.db.models
import
Sum
from
django.db.models.signals
import
pre_save
from
django.dispatch
import
receiver
from
django.utils.encoding
import
python_2_unicode_compatible
from
django.utils.translation
import
ugettext_lazy
as
_
from
repanier.const
import
*
from
repanier.fields.RepanierMoneyField
import
ModelMoneyField
from
repanier.models.producer
import
Producer
from
repanier.models.product
import
Product
,
product_pre_save
@
python_2_unicode_compatible
class
Contract
(
Product
):
def
get_calculated_stock
(
self
):
# stock : max_digits=9, decimal_places=3 => 1000000 > max(stock)
stock
=
DECIMAL_MAX_STOCK
for
contract_content
in
ContractContent
.
objects
.
filter
(
contract_id
=
self
.
id
,
product__limit_order_quantity_to_stock
=
True
,
content_quantity__gt
=
DECIMAL_ZERO
,
product__is_contract
=
False
# Disallow recursivity
).
prefetch_related
(
"product"
).
only
(
"content_quantity"
,
"product__stock"
,
"product__limit_order_quantity_to_stock"
).
order_by
(
'?'
):
stock
=
min
(
stock
,
contract_content
.
product
.
stock
//
contract_content
.
content_quantity
)
return
stock
def
get_calculated_price
(
self
):
result_set
=
ContractContent
.
objects
.
filter
(
box_id
=
self
.
id
).
aggregate
(
Sum
(
'calculated_customer_content_price'
),
Sum
(
'calculated_content_deposit'
)
)
box_price
=
result_set
[
"calculated_customer_content_price__sum"
]
\
if
result_set
[
"calculated_customer_content_price__sum"
]
is
not
None
else
DECIMAL_ZERO
box_deposit
=
result_set
[
"calculated_content_deposit__sum"
]
\
if
result_set
[
"calculated_content_deposit__sum"
]
is
not
None
else
DECIMAL_ZERO
return
box_price
,
box_deposit
class
Meta
:
proxy
=
True
verbose_name
=
_
(
"box"
)
verbose_name_plural
=
_
(
"boxes"
)
def
__str__
(
self
):
return
'%s'
%
self
.
long_name
@
receiver
(
pre_save
,
sender
=
Contract
)
def
contract_pre_save
(
sender
,
**
kwargs
):
contract
=
kwargs
[
"instance"
]
contract
.
is_contract
=
True
contract
.
producer_id
=
Producer
.
objects
.
filter
(
represent_this_buyinggroup
=
True
).
order_by
(
'?'
).
only
(
'id'
).
first
().
id
contract
.
order_unit
=
PRODUCT_ORDER_UNIT_PC
contract
.
producer_unit_price
=
contract
.
customer_unit_price
contract
.
producer_vat
=
contract
.
customer_vat
contract
.
limit_order_quantity_to_stock
=
True
# ! Important to initialise all fields of the box. Remember : a box is a product.
product_pre_save
(
sender
,
**
kwargs
)
@
python_2_unicode_compatible
class
ContractContent
(
models
.
Model
):
contract
=
models
.
ForeignKey
(
'Contract'
,
verbose_name
=
_
(
"contract"
),
null
=
True
,
blank
=
True
,
db_index
=
True
,
on_delete
=
models
.
PROTECT
)
product
=
models
.
ForeignKey
(
'Product'
,
verbose_name
=
_
(
"product"
),
related_name
=
'contract_content'
,
null
=
True
,
blank
=
True
,
db_index
=
True
,
on_delete
=
models
.
PROTECT
)
content_quantity
=
models
.
DecimalField
(
_
(
"content quantity"
),
default
=
DECIMAL_ZERO
,
max_digits
=
6
,
decimal_places
=
3
,
validators
=
[
MinValueValidator
(
0
)])
calculated_customer_content_price
=
ModelMoneyField
(
_
(
"customer content price"
),
default
=
DECIMAL_ZERO
,
max_digits
=
8
,
decimal_places
=
2
)
calculated_content_deposit
=
ModelMoneyField
(
_
(
"content deposit"
),
help_text
=
_
(
'deposit to add to the original content price'
),
default
=
DECIMAL_ZERO
,
max_digits
=
8
,
decimal_places
=
2
)
def
get_calculated_customer_content_price
(
self
):
# workaround for a display problem with Money field in the admin list_display
return
self
.
calculated_customer_content_price
+
self
.
calculated_content_deposit
get_calculated_customer_content_price
.
short_description
=
(
_
(
"customer content price"
))
get_calculated_customer_content_price
.
allow_tags
=
False
class
Meta
:
verbose_name
=
_
(
"contract content"
)
verbose_name_plural
=
_
(
"contracts content"
)
unique_together
=
(
"contract"
,
"product"
,)
index_together
=
[
[
"product"
,
"contract"
],
]
def
__str__
(
self
):
return
EMPTY_STRING
@
receiver
(
pre_save
,
sender
=
ContractContent
)
def
contract_content_pre_save
(
sender
,
**
kwargs
):
contract_content
=
kwargs
[
"instance"
]
product_id
=
contract_content
.
product_id
if
product_id
is
not
None
:
product
=
Product
.
objects
.
filter
(
id
=
product_id
).
order_by
(
'?'
).
only
(
'customer_unit_price'
,
'unit_deposit'
).
first
()
if
product
is
not
None
:
contract_content
.
calculated_customer_content_price
.
amount
=
contract_content
.
content_quantity
*
product
.
customer_unit_price
.
amount
contract_content
.
calculated_content_deposit
.
amount
=
int
(
contract_content
.
content_quantity
)
*
product
.
unit_deposit
.
amount
repanier/models/item.py
View file @
070c7057
...
...
@@ -115,8 +115,10 @@ class Item(TranslatableModel):
default
=
False
)
is_box
=
models
.
BooleanField
(
_
(
"is_box"
),
default
=
False
)
is_box_content
=
models
.
BooleanField
(
_
(
"is_box_content"
),
default
=
False
)
is_box
=
models
.
BooleanField
(
_
(
"is a box"
),
default
=
False
)
is_box_content
=
models
.
BooleanField
(
_
(
"is a box content"
),
default
=
False
)
is_contract
=
models
.
BooleanField
(
_
(
"is a contract"
),
default
=
False
)
is_contract_content
=
models
.
BooleanField
(
_
(
"is a contract content"
),
default
=
False
)
# is_membership_fee = models.BooleanField(_("is_membership_fee"), default=False)
# may_order = models.BooleanField(_("may_order"), default=True)
is_active
=
models
.
BooleanField
(
_
(
"is_active"
),
default
=
True
)
...
...
repanier/models/producer.py
View file @
070c7057
...
...
@@ -118,6 +118,20 @@ class Producer(models.Model):
get_products
.
short_description
=
(
_
(
"link to his products"
))
get_products
.
allow_tags
=
True
def
get_contracts
(
self
):
# This producer may have contrat's list
if
self
.
is_active
:
changeproductslist_url
=
urlresolvers
.
reverse
(
'admin:repanier_contract_changelist'
,
)
link
=
'<a href="%s?is_active__exact=1&producer=%s" class="btn addlink"> %s</a>'
\
%
(
changeproductslist_url
,
str
(
self
.
id
),
_
(
"his contracts"
))
return
link
return
EMPTY_STRING
get_contracts
.
short_description
=
(
_
(
"link to his contracts"
))
get_contracts
.
allow_tags
=
True
def
get_admin_date_balance
(
self
):
if
self
.
id
is
not
None
:
bank_account
=
BankAccount
.
objects
.
filter
(
...
...
repanier/static/bootstrap/css/bees-coop II/bootstrap.css
deleted
100644 → 0
View file @
9ebbb534
This diff is collapsed.
Click to expand it.
repanier/static/bootstrap/css/bees-coop II/bootstrap.css.gz
deleted
100644 → 0
View file @
9ebbb534
File deleted
repanier/static/bootstrap/css/bees-coop II/bootswatch.less
deleted
100644 → 0
View file @
9ebbb534
// Readable 3.2.0
// Bootswatch
// -----------------------------------------------------
// @import url("//fonts.googleapis.com/css?family=Raleway:400,700");
// Navbar =====================================================================
.navbar {
font-family: @headings-font-family;
&-nav,
&-form {
margin-left: 0;
margin-right: 0;
}
&-nav > li > a {
padding: @padding-base-vertical @padding-base-horizontal;
margin: 12px 6px;
border: 1px solid transparent;
border-radius: @border-radius-base;
&:hover {
border: 1px solid #ddd;
}
}
&-nav > .active > a,
&-nav > .active > a:hover {
border: 1px solid #ddd;
}
&-default .navbar-nav > .active > a:hover {
color: @navbar-default-link-hover-color;
}
&-inverse .navbar-nav > .active > a:hover {
color: @navbar-inverse-link-hover-color;
}
&-brand {
padding-top: 20px;
}
}
@media (max-width: @grid-float-breakpoint) {
.navbar {
.navbar-nav > li > a {
margin: 0;
}
}
}
// Buttons ====================================================================