This commit is contained in:
Akhilesh Darjee 2013-03-15 16:23:59 +05:30
commit d3a30d84df
117 changed files with 2516 additions and 991 deletions

View File

@ -8,7 +8,7 @@
#
# This program 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
@ -25,6 +25,8 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import _, msgprint
from stock.utils import get_buying_amount, get_sales_bom
session = webnotes.session
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
@ -95,7 +97,8 @@ class DocType(SellingController):
if not self.doc.recurring_id:
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype,
self.doc.company, self.doc.grand_total, self)
self.set_buying_amount()
self.check_prev_docstatus()
get_obj("Sales Common").update_prevdoc_detail(1,self)
@ -126,7 +129,7 @@ class DocType(SellingController):
self.check_next_docstatus()
sales_com_obj.update_prevdoc_detail(0, self)
self.make_gl_entries(is_cancel=1)
self.make_gl_entries()
def on_update_after_submit(self):
self.validate_recurring_invoice()
@ -537,8 +540,7 @@ class DocType(SellingController):
if not w:
ps = webnotes.conn.sql("select name, warehouse from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % self.doc.company)
if not ps:
msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.")
raise Exception
msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.", raise_exception=True)
elif not ps[0][1]:
msgprint("Please enter warehouse in POS Setting")
else:
@ -619,8 +621,7 @@ class DocType(SellingController):
'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
'batch_no' : cstr(d['batch_no']),
'serial_no' : d['serial_no']
})
})
def update_stock_ledger(self, update_stock):
self.values = []
@ -648,14 +649,29 @@ class DocType(SellingController):
return ret
def make_gl_entries(self, is_cancel=0):
from accounts.general_ledger import make_gl_entries
gl_entries = []
auto_inventory_accounting = webnotes.conn.get_value("Global Defaults", None,
"automatic_inventory_accounting")
abbr = self.get_company_abbr()
def make_gl_entries(self):
from accounts.general_ledger import make_gl_entries, merge_similar_entries
# parent's gl entry
gl_entries = []
self.make_customer_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
self.make_item_gl_entries(gl_entries)
# merge gl entries before adding pos entries
gl_entries = merge_similar_entries(gl_entries)
self.make_pos_gl_entries(gl_entries)
update_outstanding = cint(self.doc.is_pos) and self.doc.write_off_account and 'No' or 'Yes'
if gl_entries:
make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False)
def make_customer_gl_entry(self, gl_entries):
if self.doc.grand_total:
gl_entries.append(
self.get_gl_dict({
@ -665,10 +681,10 @@ class DocType(SellingController):
"remarks": self.doc.remarks,
"against_voucher": self.doc.name,
"against_voucher_type": self.doc.doctype,
}, is_cancel)
})
)
# tax table gl entries
def make_tax_gl_entries(self, gl_entries):
for tax in self.doclist.get({"parentfield": "other_charges"}):
if flt(tax.tax_amount):
gl_entries.append(
@ -678,11 +694,21 @@ class DocType(SellingController):
"credit": flt(tax.tax_amount),
"remarks": self.doc.remarks,
"cost_center": tax.cost_center_other_charges
}, is_cancel)
})
)
def make_item_gl_entries(self, gl_entries):
# item gl entries
for item in getlist(self.doclist, 'entries'):
auto_inventory_accounting = \
cint(webnotes.defaults.get_global_default("auto_inventory_accounting"))
if auto_inventory_accounting:
if cint(self.doc.is_pos) and cint(self.doc.update_stock):
stock_account = self.get_stock_in_hand_account()
else:
stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,)
for item in self.doclist.get({"parentfield": "entries"}):
# income account gl entries
if flt(item.amount):
gl_entries.append(
@ -692,35 +718,33 @@ class DocType(SellingController):
"credit": item.amount,
"remarks": self.doc.remarks,
"cost_center": item.cost_center
}, is_cancel)
})
)
# if auto inventory accounting enabled and stock item,
# then do stock related gl entries
if auto_inventory_accounting and item.delivery_note and \
webnotes.conn.get_value("Item", item.item_code, "is_stock_item")=="Yes":
# to-do
purchase_rate = webnotes.conn.get_value("Delivery Note Item",
item.dn_detail, "purchase_rate")
valuation_amount = purchase_rate * item.qty
# expense account gl entries
if flt(valuation_amount):
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"against": "Stock Delivered But Not Billed - %s" % (abbr,),
"debit": valuation_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
}, is_cancel)
)
gl_entries.append(
self.get_gl_dict({
"account": "Stock Delivered But Not Billed - %s" % (abbr,),
"against": item.expense_account,
"credit": valuation_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
}, is_cancel)
)
if self.doc.is_pos and self.doc.cash_bank_account and self.doc.paid_amount:
# expense account gl entries
if auto_inventory_accounting and flt(item.buying_amount):
self.check_expense_account(item)
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"against": stock_account,
"debit": item.buying_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock",
"cost_center": item.cost_center
})
)
gl_entries.append(
self.get_gl_dict({
"account": stock_account,
"against": item.expense_account,
"credit": item.buying_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
})
)
def make_pos_gl_entries(self, gl_entries):
if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount:
# POS, make payment entries
gl_entries.append(
self.get_gl_dict({
@ -730,7 +754,7 @@ class DocType(SellingController):
"remarks": self.doc.remarks,
"against_voucher": self.doc.name,
"against_voucher_type": self.doc.doctype,
}, is_cancel)
})
)
gl_entries.append(
self.get_gl_dict({
@ -738,7 +762,7 @@ class DocType(SellingController):
"against": self.doc.debit_to,
"debit": self.doc.paid_amount,
"remarks": self.doc.remarks,
}, is_cancel)
})
)
# write off entries, applicable if only pos
if self.doc.write_off_account and self.doc.write_off_amount:
@ -750,7 +774,7 @@ class DocType(SellingController):
"remarks": self.doc.remarks,
"against_voucher": self.doc.name,
"against_voucher_type": self.doc.doctype,
}, is_cancel)
})
)
gl_entries.append(
self.get_gl_dict({
@ -759,23 +783,50 @@ class DocType(SellingController):
"debit": self.doc.write_off_amount,
"remarks": self.doc.remarks,
"cost_center": self.doc.write_off_cost_center
}, is_cancel)
})
)
def set_buying_amount(self):
if cint(self.doc.is_pos) and cint(self.doc.update_stock):
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = get_sales_bom()
else:
stock_ledger_entries = item_sales_bom = None
for item in self.doclist.get({"parentfield": "entries"}):
if item.item_code in self.stock_items:
item.buying_amount = self.get_item_buying_amount(item, stock_ledger_entries,
item_sales_bom)
webnotes.conn.set_value("Sales Invoice Item", item.name,
"buying_amount", item.buying_amount)
def get_item_buying_amount(self, item, stock_ledger_entries, item_sales_bom):
item_buying_amount = 0
if stock_ledger_entries:
# is pos and update stock
item_buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty,
self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom)
elif item.delivery_note and item.dn_detail:
# against delivery note
dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail,
["buying_amount", "qty"], as_dict=1)
item_buying_rate = flt(dn_item.buying_amount) / flt(dn_item.qty)
item_buying_amount = item_buying_rate * flt(item.qty)
return item_buying_amount
update_outstanding = self.doc.is_pos and self.doc.write_off_account and 'No' or 'Yes'
merge_entries=cint(self.doc.is_pos)!=1 and 1 or 0
if gl_entries:
make_gl_entries(gl_entries, cancel=is_cancel,
update_outstanding=update_outstanding, merge_entries=merge_entries)
def check_expense_account(self, item):
if not item.expense_account:
msgprint(_("""Expense account is mandatory for item: """) + item.item_code,
raise_exception=1)
def update_c_form(self):
"""Update amended id in C-form"""
if self.doc.c_form_no and self.doc.amended_from:
webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no))
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""",
(self.doc.name, self.doc.amended_from, self.doc.c_form_no))
def check_next_docstatus(self):
submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name))

View File

@ -38,72 +38,382 @@ class TestSalesInvoice(unittest.TestCase):
si.insert()
si.submit()
self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"),
"Billed")
self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001",
"status"), "Billed")
self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"),
"Billed")
si.cancel()
self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"),
"Submitted")
self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001",
"status"), "Submitted")
self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"),
"Batched for Billing")
def test_sales_invoice_gl_entry_without_aii(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
si = webnotes.bean(webnotes.copy_doclist(test_records[1]))
si.insert()
si.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
# cancel
si.cancel()
gle_count = webnotes.conn.sql("""select count(name) from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'Yes'
order by account asc""", si.doc.name)
self.assertEquals(gle_count[0][0], 8)
def test_sales_invoice_gl_entry_with_aii_delivery_note(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self._insert_purchase_receipt()
dn = self._insert_delivery_note()
si_against_dn = webnotes.copy_doclist(test_records[1])
si_against_dn[1]["delivery_note"] = dn.doc.name
si_against_dn[1]["dn_detail"] = dn.doclist[1].name
si = webnotes.bean(si_against_dn)
si.insert()
si.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
["Stock Delivered But Not Billed - _TC", 0.0, 375.0],
[test_records[1][1]["expense_account"], 375.0, 0.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
si.cancel()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'No'
order by account asc, name asc""", si.doc.name, as_dict=1)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[si.doc.debit_to, 0.0, 630.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][1]["income_account"], 500.0, 0.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][2]["account_head"], 80.0, 0.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
[test_records[1][3]["account_head"], 50.0, 0.0],
["Stock Delivered But Not Billed - _TC", 0.0, 375.0],
["Stock Delivered But Not Billed - _TC", 375.0, 0.0],
[test_records[1][1]["expense_account"], 375.0, 0.0],
[test_records[1][1]["expense_account"], 0.0, 375.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_pos_gl_entry_with_aii(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self._insert_purchase_receipt()
self._insert_pos_settings()
pos = webnotes.copy_doclist(test_records[1])
pos[0]["is_pos"] = 1
pos[0]["update_stock"] = 1
pos[0]["posting_time"] = "12:05"
pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC"
pos[0]["paid_amount"] = 600.0
si = webnotes.bean(pos)
si.insert()
si.submit()
# check stock ledger entries
sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry`
where voucher_type = 'Sales Invoice' and voucher_no = %s""", si.doc.name, as_dict=1)[0]
self.assertTrue(sle)
self.assertEquals([sle.item_code, sle.warehouse, sle.actual_qty],
["_Test Item", "_Test Warehouse", -5.0])
# check gl entries
stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company",
"stock_in_hand_account")
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
[stock_in_hand_account, 0.0, 375.0],
[test_records[1][1]["expense_account"], 375.0, 0.0],
[si.doc.debit_to, 0.0, 600.0],
["_Test Account Bank Account - _TC", 600.0, 0.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
# cancel
si.cancel()
gl_count = webnotes.conn.sql("""select count(name)
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'Yes'
order by account asc, name asc""", si.doc.name)
self.assertEquals(gl_count[0][0], 16)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_sales_invoice_gl_entry_with_aii_no_item_code(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
si_copy = webnotes.copy_doclist(test_records[1])
si_copy[1]["item_code"] = None
si = webnotes.bean(si_copy)
si.insert()
si.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_sales_invoice_gl_entry_with_aii_non_stock_item(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
si_copy = webnotes.copy_doclist(test_records[1])
si_copy[1]["item_code"] = "_Test Non Stock Item"
si = webnotes.bean(si_copy)
si.insert()
si.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def _insert_purchase_receipt(self):
from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
as pr_test_records
pr = webnotes.bean(copy=pr_test_records[0])
pr.run_method("calculate_taxes_and_totals")
pr.insert()
pr.submit()
def _insert_delivery_note(self):
from stock.doctype.delivery_note.test_delivery_note import test_records \
as dn_test_records
dn = webnotes.bean(copy=dn_test_records[0])
dn.insert()
dn.submit()
return dn
def _insert_pos_settings(self):
ps = webnotes.bean([
{
"cash_bank_account": "_Test Account Bank Account - _TC",
"company": "_Test Company",
"conversion_rate": 1.0,
"cost_center": "_Test Cost Center - _TC",
"currency": "INR",
"doctype": "POS Setting",
"income_account": "_Test Account Bank Account - _TC",
"price_list_name": "_Test Price List",
"territory": "_Test Territory",
"warehouse": "_Test Warehouse"
}
])
ps.insert()
test_dependencies = ["Journal Voucher"]
test_records = [[
{
"naming_series": "_T-Sales Invoice-",
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"debit_to": "_Test Customer - _TC",
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"doctype": "Sales Invoice",
"due_date": "2013-01-23",
"fiscal_year": "_Test Fiscal Year 2013",
"grand_total": 561.8,
"grand_total_export": 561.8,
"net_total": 500.0,
"plc_conversion_rate": 1.0,
"posting_date": "2013-01-23",
"price_list_currency": "INR",
"price_list_name": "_Test Price List",
"territory": "_Test Territory"
},
{
"amount": 500.0,
"basic_rate": 500.0,
"description": "138-CMS Shoe",
"doctype": "Sales Invoice Item",
"export_amount": 500.0,
"export_rate": 500.0,
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
"item_name": "138-CMS Shoe",
"parentfield": "entries",
"qty": 1.0
},
{
"account_head": "_Test Account VAT - _TC",
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 30.0,
},
{
"account_head": "_Test Account Service Tax - _TC",
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 31.8,
}
]]
test_records = [
[
{
"naming_series": "_T-Sales Invoice-",
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"debit_to": "_Test Customer - _TC",
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"doctype": "Sales Invoice",
"due_date": "2013-01-23",
"fiscal_year": "_Test Fiscal Year 2013",
"grand_total": 561.8,
"grand_total_export": 561.8,
"net_total": 500.0,
"plc_conversion_rate": 1.0,
"posting_date": "2013-01-23",
"price_list_currency": "INR",
"price_list_name": "_Test Price List",
"territory": "_Test Territory"
},
{
"amount": 500.0,
"basic_rate": 500.0,
"description": "138-CMS Shoe",
"doctype": "Sales Invoice Item",
"export_amount": 500.0,
"export_rate": 500.0,
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC",
"item_name": "138-CMS Shoe",
"parentfield": "entries",
"qty": 1.0
},
{
"account_head": "_Test Account VAT - _TC",
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 30.0,
},
{
"account_head": "_Test Account Service Tax - _TC",
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 31.8,
},
{
"parentfield": "sales_team",
"doctype": "Sales Team",
"sales_person": "_Test Sales Person 1",
"allocated_percentage": 65.5,
},
{
"parentfield": "sales_team",
"doctype": "Sales Team",
"sales_person": "_Test Sales Person 2",
"allocated_percentage": 34.5,
},
],
[
{
"naming_series": "_T-Sales Invoice-",
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"debit_to": "_Test Customer - _TC",
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"doctype": "Sales Invoice",
"due_date": "2013-01-23",
"fiscal_year": "_Test Fiscal Year 2013",
"grand_total": 630.0,
"grand_total_export": 630.0,
"net_total": 500.0,
"plc_conversion_rate": 1.0,
"posting_date": "2013-03-07",
"price_list_currency": "INR",
"price_list_name": "_Test Price List",
"territory": "_Test Territory"
},
{
"item_code": "_Test Item",
"item_name": "_Test Item",
"description": "_Test Item",
"doctype": "Sales Invoice Item",
"parentfield": "entries",
"qty": 5.0,
"basic_rate": 500.0,
"amount": 500.0,
"export_rate": 500.0,
"export_amount": 500.0,
"income_account": "Sales - _TC",
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
},
{
"account_head": "_Test Account VAT - _TC",
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 80.0,
},
{
"account_head": "_Test Account Service Tax - _TC",
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"parentfield": "other_charges",
"tax_amount": 50.0,
}
],
]

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-03-05 09:11:04",
"creation": "2013-03-07 11:42:55",
"docstatus": 0,
"modified": "2013-03-07 07:03:30",
"modified": "2013-03-11 14:58:50",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -30,7 +30,8 @@
"fieldname": "barcode",
"fieldtype": "Data",
"label": "Barcode",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -42,6 +43,7 @@
"oldfieldtype": "Link",
"options": "Item",
"print_hide": 0,
"read_only": 0,
"reqd": 0,
"search_index": 1
},
@ -63,6 +65,7 @@
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"print_hide": 1,
"read_only": 0,
"reqd": 1,
"search_index": 0
},
@ -74,6 +77,7 @@
"oldfieldname": "description",
"oldfieldtype": "Text",
"print_width": "200px",
"read_only": 0,
"reqd": 1,
"width": "200px"
},
@ -84,6 +88,7 @@
"label": "Qty",
"oldfieldname": "qty",
"oldfieldtype": "Currency",
"read_only": 0,
"reqd": 0
},
{
@ -102,6 +107,7 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
"read_only": 0,
"reqd": 0
},
{
@ -111,7 +117,8 @@
"label": "Discount (%)",
"oldfieldname": "adj_rate",
"oldfieldtype": "Float",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -121,6 +128,7 @@
"oldfieldname": "export_rate",
"oldfieldtype": "Currency",
"options": "currency",
"read_only": 0,
"reqd": 1
},
{
@ -155,6 +163,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 0,
"reqd": 1,
"search_index": 0
},
@ -179,7 +188,8 @@
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -192,9 +202,20 @@
"options": "Account",
"print_hide": 1,
"print_width": "120px",
"read_only": 0,
"reqd": 1,
"width": "120px"
},
{
"doctype": "DocField",
"fieldname": "expense_account",
"fieldtype": "Link",
"hidden": 1,
"in_filter": 1,
"label": "Expense Account",
"options": "Account",
"print_hide": 1
},
{
"doctype": "DocField",
"fieldname": "cost_center",
@ -206,6 +227,7 @@
"options": "Cost Center",
"print_hide": 1,
"print_width": "120px",
"read_only": 0,
"reqd": 0,
"width": "120px"
},
@ -217,7 +239,8 @@
"label": "Serial No",
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"print_hide": 0
"print_hide": 0,
"read_only": 0
},
{
"doctype": "DocField",
@ -225,7 +248,8 @@
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -249,7 +273,8 @@
"label": "Brand Name",
"oldfieldname": "brand",
"oldfieldtype": "Data",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -328,7 +353,8 @@
"fieldname": "time_log_batch",
"fieldtype": "Link",
"label": "Time Log Batch",
"options": "Time Log Batch"
"options": "Time Log Batch",
"read_only": 0
},
{
"doctype": "DocField",
@ -353,6 +379,17 @@
"print_hide": 1,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "buying_amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Buying Amount",
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"doctype": "DocField",
@ -361,6 +398,7 @@
"label": "Page Break",
"no_copy": 1,
"print_hide": 1,
"read_only": 0,
"report_hide": 1
}
]

View File

@ -16,7 +16,7 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt, cstr
from webnotes.utils import flt, cstr, now
from webnotes.model.doc import Document
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
@ -109,5 +109,7 @@ def validate_total_debit_credit(total_debit, total_credit):
(total_debit - total_credit), raise_exception=1)
def set_as_cancel(voucher_type, voucher_no):
webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes'
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes',
modified=%s, modified_by=%s
where voucher_type=%s and voucher_no=%s""",
(now(), webnotes.session.user, voucher_type, voucher_no))

View File

@ -109,11 +109,11 @@ erpnext.AccountsChart = Class.extend({
},
onrender: function(treenode) {
if (ctype == 'Account') {
var bal = treenode.data && treenode.data.balance.split(' ') || ['',''];
if (bal && flt(bal[1])) {
if (ctype == 'Account' && treenode.data) {
if(treenode.data.balance) {
treenode.parent.append('<span class="balance-area">'
+ format_currency(bal[1], bal[0]) + '</span>');
+ format_currency(treenode.data.balance, treenode.data.currency)
+ '</span>');
}
}
}

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals
import webnotes
import webnotes.defaults
from webnotes.utils import flt
from accounts.utils import get_balance_on
@webnotes.whitelist()
@ -53,6 +53,7 @@ def get_children():
currency = webnotes.conn.sql("select default_currency from `tabCompany` where name = %s", company)[0][0]
for each in acc:
bal = get_balance_on(each.get("value"))
each['balance'] = currency + ' ' + str(bal or 0)
each["currency"] = currency
each["balance"] = flt(bal)
return acc

View File

@ -71,9 +71,11 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({
setup_filters: function() {
var me = this;
this._super();
this.filter_inputs.pl_or_bs.change(function() {
me.filter_inputs.refresh.click();
}).add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
this.trigger_refresh_on_change(["pl_or_bs"]);
this.filter_inputs.pl_or_bs
.add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
this.setup_plot_check();
},
init_filter_values: function() {

View File

@ -108,7 +108,7 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({
// filter accounts options by company
this.filter_inputs.company.change(function() {
me.setup_account_filter(this);
me.filter_inputs.refresh.click();
me.set_route()
});
this.filter_inputs.account.change(function() {

View File

@ -25,7 +25,7 @@ def execute(filters=None):
for row in delivery_note_items:
selling_amount = flt(row.amount)
buying_amount = get_buying_amount(row.item_code, row.warehouse,
row.qty, row.name, row.item_row, stock_ledger_entries, item_sales_bom)
row.qty, "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom)
if selling_amount:
gross_profit = selling_amount - buying_amount
gross_profit_percent = (gross_profit / selling_amount) * 100.0

View File

@ -21,7 +21,7 @@
wn.provide("erpnext.buying");
erpnext.buying.BuyingController = erpnext.utils.Controller.extend({
erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
setup: function() {
var me = this;
@ -68,15 +68,15 @@ erpnext.buying.BuyingController = erpnext.utils.Controller.extend({
callback: function(r) {
if(!r.exc) {
me.price_list_currency();
if (callback_fn) callback_fn(me.frm.doc, me.frm.doc.doctype,
me.frm.doc.name);
if (typeof callback_fn === "function")
callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
}
}
});
} else {
me.price_list_currency();
if (callback_fn) callback_fn(me.frm.doc, me.frm.doc.doctype,
me.frm.doc.name);
if (typeof callback_fn === "function")
callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
}
}
},

View File

@ -132,6 +132,10 @@ class DocType(BuyingController):
for d in getlist(self.doclist, 'po_details'):
#1. Check if is_stock_item == 'Yes'
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
# this happens when item is changed from non-stock to stock item
if not d.warehouse:
continue
ind_qty, po_qty = 0, flt(d.qty) * flt(d.conversion_factor)
if is_stopped:
po_qty = flt(d.qty) > flt(d.received_qty) and \

View File

@ -120,19 +120,9 @@ erpnext.PurchaseAnalytics = wn.views.TreeGridReport.extend({
setup_filters: function() {
var me = this;
this._super();
this.filter_inputs.value_or_qty.change(function() {
me.filter_inputs.refresh.click();
});
this.filter_inputs.tree_type.change(function() {
me.filter_inputs.refresh.click();
});
this.filter_inputs.based_on.change(function() {
me.filter_inputs.refresh.click();
});
this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
this.show_zero_check()
this.setup_plot_check();
},

View File

@ -21,8 +21,11 @@ from webnotes.utils import flt
from utilities.transaction_base import TransactionBase
class AccountsController(TransactionBase):
def get_gl_dict(self, args, cancel):
def get_gl_dict(self, args, cancel=None):
"""this method populates the common properties of a gl entry record"""
if cancel is None:
cancel = (self.doc.docstatus == 2)
gl_dict = {
'company': self.doc.company,
'posting_date': self.doc.posting_date,

View File

@ -37,4 +37,27 @@ class SellingController(AccountsController):
self.doc.grand_total or self.doc.rounded_total, company_currency)
if self.meta.get_field("in_words_export"):
self.doc.in_words_export = money_in_words(disable_rounded_total and
self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency)
self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency)
def get_stock_ledger_entries(self):
item_list, warehouse_list = self.get_distinct_item_warehouse()
if item_list and warehouse_list:
return webnotes.conn.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, posting_date, posting_time, stock_value,
warehouse, actual_qty as qty from `tabStock Ledger Entry`
where ifnull(`is_cancelled`, "No") = "No" and company = %s
and item_code in (%s) and warehouse in (%s)
order by item_code desc, warehouse desc, posting_date desc,
posting_time desc, name desc""" %
('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))),
tuple([self.doc.company] + item_list + warehouse_list), as_dict=1)
def get_distinct_item_warehouse(self):
item_list = []
warehouse_list = []
for item in self.doclist.get({"parentfield": self.fname}) \
+ self.doclist.get({"parentfield": "packing_details"}):
item_list.append(item.item_code)
warehouse_list.append(item.warehouse)
return list(set(item_list)), list(set(warehouse_list))

View File

@ -26,6 +26,10 @@
<td><a href="http://httpd.apache.org">Apache HTTPD web server</a></td>
<td>The Number One HTTP Server On The Internet.</td>
</tr>
<tr>
<td><a href="http://memcached.org/">Memcached</a></td>
<td>Free & open source, high-performance, distributed memory object caching system.</td>
</tr>
<tr>
<td><a href="http://python.org/">Python Programming Language</a></td>
<td>The "batteries included" language that lets you write elegant code, quickly.<br><br>Python Libraries:

View File

@ -1,6 +1,15 @@
erpnext.updates = [
["12th March", ["Updates to website module. Added more options in Style Settings and Website Settings."]],
["5th March", ["Refactored Upload Attendance Tool"]],
["4th March", ["Lead organization added in Quotation classic/spartan/modern print format"]],
["1st March", [
"Time Log, Time Log Batch: Created feature to batch Time Logs so that they can be tracked for billing."
"Time Log, Time Log Batch: Created feature to batch Time Logs so that they can be tracked for billing.",
"Sub-contracting code refactored for PO",
]],
["28th February", [
"Datatype validation in Voucher Import Tool",
"Fixes for conversion factor in old invoices",
"Fixed asynchronus issue in purchase cycle"
]],
["27th February", [
"Time Log: Created Time Log System, with Calendar View."

View File

@ -17,7 +17,7 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import getdate, validate_email_add
from webnotes.utils import getdate, validate_email_add, cstr
from webnotes.model.doc import make_autoname
from webnotes import msgprint, _
@ -104,7 +104,7 @@ class DocType:
fname, fid = file_args.split(",")
if self.doc.image == fname:
new_file_args = fname + "," + fid
file_list = profile_wrapper.doc.file_list.split("\n")
file_list = cstr(profile_wrapper.doc.file_list).split("\n")
if new_file_args not in file_list:
file_list += [new_file_args]
profile_wrapper.doc.file_list = "\n".join(file_list)

View File

@ -18,7 +18,7 @@
wn.require("public/app/js/utils.js");
wn.provide("erpnext.hr");
erpnext.hr.AttendanceControlPanel = erpnext.utils.Controller.extend({
erpnext.hr.AttendanceControlPanel = wn.ui.form.Controller.extend({
onload: function() {
this.frm.set_value("att_fr_date", get_today());
this.frm.set_value("att_to_date", get_today());

View File

@ -1 +1 @@
SELECT DISTINCT `tabAttendance`.employee, `tabAttendance`.employee_name FROM `tabAttendance` WHERE `tabAttendance`.fiscal_year like '%(fiscal_year)s%%' AND `tabAttendance`.`company` like '%(company)s%%' AND `tabAttendance`.`employee` like '%(employee)s%%'
SELECT DISTINCT `tabAttendance`.employee, `tabEmployee`.employee_name FROM `tabAttendance`, `tabEmployee` WHERE `tabEmployee`.name = `tabAttendance`.employee and `tabAttendance`.fiscal_year like '%(fiscal_year)s%%' AND `tabAttendance`.company like '%(company)s%%' AND `tabAttendance`.employee like '%(employee)s%%'

View File

@ -1,13 +0,0 @@
import webnotes
def execute():
webnotes.reload_doc("website", "doctype", "web_page")
webnotes.reload_doc("website", "doctype", "blog")
webnotes.reload_doc("stock", "doctype", "item")
webnotes.reload_doc("setup", "doctype", "item_group")
# build wn-web.js and wn-web.css
from website.helpers.make_web_include_files import make
make()
import website.utils
website.utils.clear_cache()

View File

@ -1,6 +0,0 @@
import webnotes
def execute():
from website.utils import clear_cache
clear_cache()

View File

@ -0,0 +1,9 @@
import webnotes
def execute():
webnotes.reload_doc('website', 'doctype', 'blogger')
webnotes.rename_doc("DocType", "Blog", "Blog Post", force=True)
webnotes.reload_doc('website', 'doctype', 'blog_post')
webnotes.conn.sql('''update tabBlogger set posts=(select count(*)
from `tabBlog Post` where ifnull(blogger,"")=tabBlogger.name)''')
webnotes.conn.sql("""update `tabBlog Post` set published_on=date(creation)""")

View File

@ -0,0 +1,10 @@
import webnotes
def execute():
dn_list = webnotes.conn.sql("""select name from `tabDelivery Note` where docstatus < 2""")
for dn in dn_list:
webnotes.bean("Delivery Note", dn[0]).set_buying_amount()
si_list = webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus < 2""")
for si in si_list:
webnotes.bean("Sales Invoice", si[0]).set_buying_amount()

View File

@ -0,0 +1,30 @@
import webnotes
def execute():
# delete wrong gle entries created due to a bug in make_gl_entries of Account Controller
# when using payment reconciliation
res = webnotes.conn.sql_list("""select distinct gl1.voucher_no
from `tabGL Entry` gl1, `tabGL Entry` gl2
where
(date(gl1.modified) between "2013-03-11" and "2013-03-15")
and date(gl1.modified) = date(gl2.modified)
and gl1.voucher_no = gl2.voucher_no
and gl1.voucher_type = "Journal Voucher"
and gl1.voucher_type = gl2.voucher_type
and gl1.posting_date = gl2.posting_date
and gl1.account = gl2.account
and ifnull(gl1.cost_center, "") = ifnull(gl2.cost_center, "")
and ifnull(gl1.is_cancelled, 'No') = 'No' and ifnull(gl2.is_cancelled, 'No') = 'No'
and ifnull(gl1.against_voucher, '') = ifnull(gl2.against_voucher, '')
and ifnull(gl1.against_voucher_type, '') = ifnull(gl2.against_voucher_type, '')
and gl1.remarks = gl2.remarks
and ifnull(gl1.debit, 0) = ifnull(gl2.credit, 0)
and ifnull(gl1.credit, 0) = ifnull(gl2.debit, 0)
and gl1.name > gl2.name""")
for r in res:
webnotes.conn.sql("""update `tabGL Entry` set `is_cancelled`='Yes'
where voucher_type='Journal Voucher' and voucher_no=%s""", r)
jv = webnotes.bean("Journal Voucher", r)
jv.run_method("make_gl_entries")

View File

@ -16,7 +16,9 @@
from __future__ import unicode_literals
patch_list = [
"execute:webnotes.reload_doc('core', 'doctype', 'report') # 2013-03-07",
"execute:webnotes.reload_doc('core', 'doctype', 'docfield')",
"execute:webnotes.reload_doc('core', 'doctype', 'report')",
"execute:webnotes.reload_doc('core', 'doctype', 'doctype')",
"patches.mar_2012.so_rv_mapper_fix",
"patches.mar_2012.clean_property_setter",
"patches.april_2012.naming_series_patch",
@ -130,7 +132,6 @@ patch_list = [
"patches.december_2012.fix_default_print_format",
"patches.december_2012.file_list_rename",
"patches.december_2012.replace_createlocal",
"patches.december_2012.clear_web_cache",
"patches.december_2012.remove_quotation_next_contact",
"patches.december_2012.stock_entry_cleanup",
"patches.december_2012.production_order_naming_series",
@ -187,7 +188,6 @@ patch_list = [
"execute:webnotes.delete_doc('DocType', 'Service Order Detail')",
"execute:webnotes.delete_doc('DocType', 'Service Quotation Detail')",
"patches.february_2013.p06_material_request_mappers",
"patches.february_2013.p07_clear_web_cache",
"execute:webnotes.delete_doc('Page', 'Query Report')",
"execute:webnotes.delete_doc('Search Criteria', 'employeewise_balance_leave_report')",
"execute:webnotes.delete_doc('Search Criteria', 'employee_leave_balance_report')",
@ -209,4 +209,7 @@ patch_list = [
"execute:webnotes.conn.sql('update tabDocPerm set `submit`=1, `cancel`=1, `amend`=1 where parent=\"Time Log\"')",
"execute:webnotes.delete_doc('DocType', 'Attendance Control Panel')",
"patches.march_2013.p02_get_global_default",
"patches.march_2013.p03_rename_blog_to_blog_post",
"execute:webnotes.reload_doc('hr', 'search_criteria', 'monthly_attendance_details')",
"patches.march_2013.p05_payment_reconciliation",
]

View File

@ -18,7 +18,7 @@ wn.provide("erpnext.projects");
cur_frm.add_fetch("project", "company", "company");
erpnext.projects.Task = erpnext.utils.Controller.extend({
erpnext.projects.Task = wn.ui.form.Controller.extend({
setup: function() {
this.frm.fields_dict.project.get_query = function() {
return "select name from `tabProject` \
@ -29,7 +29,8 @@ erpnext.projects.Task = erpnext.utils.Controller.extend({
project: function() {
if(this.frm.doc.project) {
get_server_fields('get_project_details', '','', doc, cdt, cdn, 1);
get_server_fields('get_project_details', '','', this.frm.doc, this.frm.doc.doctype,
this.frm.doc.name, 1);
}
},

View File

@ -16,7 +16,7 @@
wn.provide("erpnext.stock");
erpnext.stock.StockController = erpnext.utils.Controller.extend({
erpnext.stock.StockController = wn.ui.form.Controller.extend({
show_stock_ledger: function() {
var me = this;
this.frm.add_custom_button("Show Stock Ledger", function() {

View File

@ -166,22 +166,24 @@ pscript.feature_dict = {
'Address': {'fields':['sales_partner']},
'Contact': {'fields':['sales_partner']},
'Customer': {'fields':['sales_team']},
'Delivery Note': {'fields':['sales_team','Packing List']},
'Delivery Note': {'fields':['sales_team','packing_list']},
'Item': {'fields':['item_customer_details']},
'Sales Invoice': {'fields':['sales_team']},
'Sales Order': {'fields':['sales_team','Packing List']}
'Sales Invoice': {'fields':['sales_team', 'packing_list']},
'Sales Order': {'fields':['sales_team','packing_list']}
},
'fs_more_info': {
'Delivery Note': {'fields':['More Info']},
'Opportunity': {'fields':['More Info']},
'Material Request': {'fields':['More Info']},
'Lead': {'fields':['More Info']},
'Purchase Invoice': {'fields':['More Info']},
'Purchase Order': {'fields':['More Info']},
'Purchase Receipt': {'fields':['More Info']},
'Quotation': {'fields':['More Info']},
'Sales Invoice': {'fields':['More Info']},
'Sales Order': {'fields':['More Info']},
"Customer Issue": {"fields": ["more_info"]},
'Material Request': {'fields':['more_info']},
'Lead': {'fields':['more_info']},
'Opportunity': {'fields':['more_info']},
'Purchase Invoice': {'fields':['more_info']},
'Purchase Order': {'fields':['more_info']},
'Purchase Receipt': {'fields':['more_info']},
'Supplier Quotation': {'fields':['more_info']},
'Quotation': {'fields':['more_info']},
'Sales Invoice': {'fields':['more_info']},
'Sales Order': {'fields':['more_info']},
'Delivery Note': {'fields':['more_info']},
},
'fs_quality': {
'Item': {'fields':['Item Inspection Criteria','inspection_required']},
@ -199,25 +201,23 @@ pscript.feature_dict = {
}
$(document).bind('form_refresh', function() {
for(sys_feat in sys_defaults)
{
if(sys_defaults[sys_feat]=='0' && (sys_feat in pscript.feature_dict)) //"Features to hide" exists
{
if(cur_frm.doc.doctype in pscript.feature_dict[sys_feat])
{
for(fort in pscript.feature_dict[sys_feat][cur_frm.doc.doctype])
{
if(fort=='fields')
for(sys_feat in sys_defaults) {
if(sys_defaults[sys_feat]=='0'
&& (sys_feat in pscript.feature_dict)) { //"Features to hide" exists
if(cur_frm.doc.doctype in pscript.feature_dict[sys_feat]) {
for(fort in pscript.feature_dict[sys_feat][cur_frm.doc.doctype]) {
if(fort=='fields') {
hide_field(pscript.feature_dict[sys_feat][cur_frm.doc.doctype][fort]);
else if(cur_frm.fields_dict[fort])
{
} else if(cur_frm.fields_dict[fort]) {
for(grid_field in pscript.feature_dict[sys_feat][cur_frm.doc.doctype][fort])
cur_frm.fields_dict[fort].grid.set_column_disp(pscript.feature_dict[sys_feat][cur_frm.doc.doctype][fort][grid_field], false);
}
else
} else {
msgprint('Grid "'+fort+'" does not exists');
}
}
}
}
}
})

View File

@ -134,6 +134,7 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
var data = wn.report_dump.data["Stock Ledger Entry"];
this.item_warehouse = {};
this.serialized_buying_rates = this.get_serialized_buying_rates();
for(var i=0, j=data.length; i<j; i++) {
var sl = data[i];

View File

@ -44,8 +44,9 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
} else {
// outgoing
if(is_fifo) {
if(sl.serial_no) {
var value_diff = -1 * this.get_serialized_value_diff(sl);
} else if(is_fifo) {
var value_diff = this.get_fifo_value_diff(wh, sl);
} else {
// average rate for weighted average
@ -102,4 +103,34 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
wh.fifo_stack = fifo_stack.reverse();
return -fifo_value_diff;
},
get_serialized_value_diff: function(sl) {
var me = this;
var value_diff = 0.0;
$.each(sl.serial_no.trim().split("\n"), function(i, serial_no) {
if(serial_no) {
value_diff += flt(me.serialized_buying_rates[serial_no]);
}
});
return value_diff;
},
get_serialized_buying_rates: function() {
var serialized_buying_rates = {};
$.each(wn.report_dump.data["Stock Ledger Entry"], function(i, sle) {
if(sle.qty > 0 && sle.serial_no) {
$.each(sle.serial_no.trim().split("\n"), function(i, sr) {
if(sr && sle.incoming_rate !== undefined) {
serialized_buying_rates[sr] = flt(sle.incoming_rate);
}
});
}
});
return serialized_buying_rates;
},
});

View File

@ -23,35 +23,4 @@ erpnext.get_currency = function(company) {
return wn.model.get(":Company", company).default_currency || wn.boot.sysdefaults.currency;
else
return wn.boot.sysdefaults.currency;
}
// TODO
erpnext.utils.Controller = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.setup && this.setup();
},
onload_post_render: function() {
if(this.frm.doc.__islocal) {
this.setup_defaults();
}
},
setup_defaults: function() {
var me = this;
var defaults = {
posting_date: wn.datetime.get_today(),
posting_time: wn.datetime.now_time()
}
$.each(defaults, function(k, v) {
if(!me.frm.doc[k]) me.frm.set_value(k, v);
});
},
refresh: function() {
erpnext.hide_naming_series();
}
});
}

View File

@ -341,12 +341,10 @@ class DocType(TransactionBase):
# ========================================================================
# it indicates % contribution of sales person in sales
def get_allocated_sum(self,obj):
sum = 0
for d in getlist(obj.doclist,'sales_team'):
sum += flt(d.allocated_percentage)
if (flt(sum) != 100) and getlist(obj.doclist,'sales_team'):
msgprint("Total Allocated % of Sales Persons should be 100%")
raise Exception
sales_team_list = obj.doclist.get({"parentfield": "sales_team"})
total_allocation = sum([flt(d.allocated_percentage) for d in sales_team_list])
if sales_team_list and total_allocation != 100.0:
msgprint("Total Allocated %% of Sales Persons should be 100%", raise_exception=True)
# Check Conversion Rate (i.e. it will not allow conversion rate to be 1 for Currency other than default currency set in Global Defaults)
# ===========================================================================

View File

@ -156,9 +156,13 @@ class DocType(SellingController):
f = [d.item_code, d.description]
#check item is stock item
st_itm = sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
st_itm = sql("select is_stock_item from `tabItem` where name = %s", d.item_code)
if st_itm and st_itm[0][0] == 'Yes':
if not d.reserved_warehouse:
msgprint("""Please enter Reserved Warehouse for item %s
as it is stock Item""" % d.item_code, raise_exception=1)
if e in check_list:
msgprint("Item %s has been entered twice." % d.item_code)
else:
@ -333,10 +337,6 @@ class DocType(SellingController):
def update_stock_ledger(self, update_stock, is_stopped = 0):
for d in self.get_item_list(is_stopped):
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['reserved_warehouse']:
msgprint("""Please enter Reserved Warehouse for item %s
as it is stock Item""" % d['item_code'], raise_exception=1)
args = {
"item_code": d['item_code'],
"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),

View File

@ -65,7 +65,7 @@ class TestSalesOrder(unittest.TestCase):
# submit dn
dn = self.create_dn_against_so(so)
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 5.0)
# stop so
so.load_from_db()
@ -75,7 +75,7 @@ class TestSalesOrder(unittest.TestCase):
# unstop so
so.load_from_db()
so.obj.unstop_sales_order()
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 5.0)
# cancel dn
dn.cancel()
@ -151,9 +151,9 @@ class TestSalesOrder(unittest.TestCase):
dn = self.create_dn_against_so(so)
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].reserved_warehouse, 30.0)
so.doclist[1].reserved_warehouse, 25.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].reserved_warehouse, 12.0)
so.doclist[1].reserved_warehouse, 10.0)
# stop so
so.load_from_db()
@ -168,9 +168,9 @@ class TestSalesOrder(unittest.TestCase):
so.load_from_db()
so.obj.unstop_sales_order()
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
so.doclist[1].reserved_warehouse, 30.0)
so.doclist[1].reserved_warehouse, 25.0)
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
so.doclist[1].reserved_warehouse, 12.0)
so.doclist[1].reserved_warehouse, 10.0)
# cancel dn
dn.cancel()
@ -234,8 +234,8 @@ test_records = [
"price_list_name": "_Test Price List",
"territory": "_Test Territory",
"transaction_date": "2013-02-21",
"grand_total": 500.0,
"grand_total_export": 500.0,
"grand_total": 1000.0,
"grand_total_export": 1000.0,
},
{
"description": "CPU",
@ -244,9 +244,9 @@ test_records = [
"item_name": "CPU",
"parentfield": "sales_order_details",
"qty": 10.0,
"basic_rate": 50.0,
"export_rate": 50.0,
"amount": 500.0,
"basic_rate": 100.0,
"export_rate": 100.0,
"amount": 1000.0,
"reserved_warehouse": "_Test Warehouse",
}
],

View File

@ -122,18 +122,8 @@ erpnext.SalesAnalytics = wn.views.TreeGridReport.extend({
setup_filters: function() {
var me = this;
this._super();
this.filter_inputs.value_or_qty.change(function() {
me.filter_inputs.refresh.click();
});
this.filter_inputs.tree_type.change(function() {
me.filter_inputs.refresh.click();
});
this.filter_inputs.based_on.change(function() {
me.filter_inputs.refresh.click();
});
this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
this.show_zero_check()
this.setup_plot_check();

View File

@ -4,5 +4,19 @@ test_records = [
"sales_person_name": "_Test Sales Person",
"parent_sales_person": "All Sales Persons",
"is_group": "No"
}],
[{
"doctype": "Sales Person",
"sales_person_name": "_Test Sales Person 1",
"parent_sales_person": "All Sales Persons",
"is_group": "No"
}],
[{
"doctype": "Sales Person",
"sales_person_name": "_Test Sales Person 2",
"parent_sales_person": "All Sales Persons",
"is_group": "No"
}]
]

View File

@ -97,7 +97,7 @@ class DocType:
self.create_email_digest()
webnotes.clear_cache()
msgprint("Company setup is complete")
msgprint("Company setup is complete. Please refresh the page before continuing.")
import webnotes.utils
user_fullname = (args.get('first_name') or '') + (args.get('last_name')

View File

@ -45,7 +45,7 @@ wn.module_page["Setup"] = [
},
{
"doctype":"Workflow",
label:wn._("Workfow"),
label:wn._("Workflow"),
"description":wn._("Set workflow rules.")
},
{
@ -98,12 +98,6 @@ wn.module_page["Setup"] = [
label:wn._("Print Heading"),
"description":wn._("Add headers for standard print formats")
},
{
"route":"Form/Style Settings/Style Settings",
doctype:wn._("Style Settings"),
label:wn._("Style Settings"),
"description":wn._("Change background fonts etc")
}
]
},
{

View File

@ -86,8 +86,9 @@ data_map = {
"order_by": "name"
},
"Stock Ledger Entry": {
"columns": ["name", "posting_date", "posting_time", "item_code", "warehouse", "actual_qty as qty",
"voucher_type", "voucher_no", "ifnull(incoming_rate,0) as incoming_rate", "stock_uom"],
"columns": ["name", "posting_date", "posting_time", "item_code", "warehouse",
"actual_qty as qty", "voucher_type", "voucher_no",
"ifnull(incoming_rate,0) as incoming_rate", "stock_uom", "serial_no"],
"conditions": ["ifnull(is_cancelled, 'No')='No'"],
"order_by": "posting_date, posting_time, name",
"links": {

View File

@ -156,7 +156,7 @@ class DocType(SellingController):
if not self.doc.billing_status: self.doc.billing_status = 'Not Billed'
if not self.doc.installation_status: self.doc.installation_status = 'Not Installed'
def validate_mandatory(self):
if self.doc.amended_from and not self.doc.amendment_date:
msgprint("Please Enter Amendment Date")
@ -225,7 +225,12 @@ class DocType(SellingController):
bin = sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
def on_update(self):
self.doclist = get_obj('Sales Common').make_packing_list(self,'delivery_note_details')
sl = get_obj('Stock Ledger')
sl.scrub_serial_nos(self)
sl.scrub_serial_nos(self, 'packing_details')
def on_submit(self):
self.validate_packed_qty()
@ -252,6 +257,7 @@ class DocType(SellingController):
self.credit_limit()
self.set_buying_amount()
self.make_gl_entries()
# set DN status
@ -332,10 +338,10 @@ class DocType(SellingController):
self.values = []
for d in self.get_item_list():
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Please enter Warehouse for item %s as it is stock item"
% d['item_code'], raise_exception=1)
# this happens when item is changed from non-stock to stock item
if not d["warehouse"]:
continue
if d['reserved_qty'] < 0 :
# Reduce reserved qty from reserved warehouse mentioned in so
args = {
@ -387,13 +393,28 @@ class DocType(SellingController):
if amount != 0:
total = (amount/self.doc.net_total)*self.doc.grand_total
get_obj('Sales Common').check_credit(self, total)
def on_update(self):
self.doclist = get_obj('Sales Common').make_packing_list(self,'delivery_note_details')
sl = get_obj('Stock Ledger')
sl.scrub_serial_nos(self)
sl.scrub_serial_nos(self, 'packing_details')
def set_buying_amount(self):
from stock.utils import get_buying_amount, get_sales_bom
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = get_sales_bom()
if stock_ledger_entries:
for item in self.doclist.get({"parentfield": "delivery_note_details"}):
item.buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty,
self.doc.doctype, self.doc.name, item.name, stock_ledger_entries,
item_sales_bom)
webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount",
item.buying_amount)
self.validate_warehouse()
def validate_warehouse(self):
for d in self.get_item_list():
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Please enter Warehouse for item %s as it is stock item"
% d['item_code'], raise_exception=1)
def make_gl_entries(self):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
@ -426,38 +447,6 @@ class DocType(SellingController):
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
def get_total_buying_amount(self):
from stock.utils import get_buying_amount, get_sales_bom
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = get_sales_bom()
total_buying_amount = 0
if stock_ledger_entries:
for item in self.doclist.get({"parentfield": "delivery_note_details"}):
buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty,
self.doc.name, item.name, stock_ledger_entries, item_sales_bom)
total_buying_amount += buying_amount
total_buying_amount = sum([item.buying_amount for item in
self.doclist.get({"parentfield": "delivery_note_details"})])
return total_buying_amount
def get_stock_ledger_entries(self):
item_list, warehouse_list = self.get_distinct_item_warehouse()
if item_list and warehouse_list:
return webnotes.conn.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, posting_date, posting_time, stock_value,
warehouse, actual_qty as qty from `tabStock Ledger Entry`
where ifnull(`is_cancelled`, "No") = "No" and company = %s
and item_code in (%s) and warehouse in (%s)
order by item_code desc, warehouse desc, posting_date desc,
posting_time desc, name desc""" %
('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))),
tuple([self.doc.company] + item_list + warehouse_list), as_dict=1)
def get_distinct_item_warehouse(self):
item_list = []
warehouse_list = []
for item in self.doclist.get({"parentfield": "delivery_note_details"}) \
+ self.doclist.get({"parentfield": "packing_details"}):
item_list.append(item.item_code)
warehouse_list.append(item.warehouse)
return list(set(item_list)), list(set(warehouse_list))

View File

@ -48,6 +48,8 @@ class TestDeliveryNote(unittest.TestCase):
def test_delivery_note_gl_entry(self):
webnotes.conn.sql("""delete from `tabBin`""")
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self.assertEqual(cint(webnotes.defaults.get_global_default("auto_inventory_accounting")), 1)
@ -109,7 +111,7 @@ test_records = [
"description": "CPU",
"doctype": "Delivery Note Item",
"item_code": "_Test Item",
"item_name": "CPU",
"item_name": "_Test Item",
"parentfield": "delivery_note_details",
"qty": 5.0,
"basic_rate": 100.0,

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-02-22 01:28:00",
"creation": "2013-03-07 11:42:59",
"docstatus": 0,
"modified": "2013-03-07 07:03:20",
"modified": "2013-03-07 15:46:43",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -30,7 +30,8 @@
"fieldname": "barcode",
"fieldtype": "Data",
"label": "Barcode",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -42,6 +43,7 @@
"oldfieldtype": "Link",
"options": "Item",
"print_width": "150px",
"read_only": 0,
"reqd": 1,
"search_index": 1,
"width": "150px"
@ -64,6 +66,7 @@
"oldfieldtype": "Data",
"print_hide": 1,
"print_width": "150px",
"read_only": 0,
"reqd": 1,
"width": "150px"
},
@ -75,6 +78,7 @@
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"print_width": "300px",
"read_only": 0,
"reqd": 1,
"width": "300px"
},
@ -87,6 +91,7 @@
"oldfieldname": "qty",
"oldfieldtype": "Currency",
"print_width": "100px",
"read_only": 0,
"reqd": 1,
"width": "100px"
},
@ -115,6 +120,7 @@
"options": "currency",
"print_hide": 1,
"print_width": "100px",
"read_only": 0,
"reqd": 0,
"width": "100px"
},
@ -128,6 +134,7 @@
"oldfieldtype": "Float",
"print_hide": 1,
"print_width": "100px",
"read_only": 0,
"width": "100px"
},
{
@ -140,6 +147,7 @@
"options": "currency",
"print_hide": 0,
"print_width": "150px",
"read_only": 0,
"reqd": 0,
"width": "150px"
},
@ -181,6 +189,7 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"print_width": "150px",
"read_only": 0,
"reqd": 0,
"width": "150px"
},
@ -208,6 +217,7 @@
"options": "Warehouse",
"print_hide": 1,
"print_width": "100px",
"read_only": 0,
"width": "100px"
},
{
@ -219,7 +229,8 @@
"no_copy": 1,
"oldfieldname": "serial_no",
"oldfieldtype": "Text",
"print_hide": 0
"print_hide": 0,
"read_only": 0
},
{
"doctype": "DocField",
@ -229,7 +240,8 @@
"oldfieldname": "batch_no",
"oldfieldtype": "Link",
"options": "Batch",
"print_hide": 1
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
@ -375,6 +387,17 @@
"print_hide": 1,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "buying_amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Buying Amount",
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"doctype": "DocField",
@ -383,6 +406,7 @@
"label": "Page Break",
"oldfieldname": "page_break",
"oldfieldtype": "Check",
"print_hide": 1
"print_hide": 1,
"read_only": 0
}
]

View File

@ -20,15 +20,12 @@ import webnotes
from webnotes.utils import cstr, flt
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes import msgprint
from webnotes import msgprint, _
sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
from webnotes.model.controller import DocListController
class DocType(DocListController):
def get_tax_rate(self, tax_type):
rate = sql("select tax_rate from tabAccount where name = %s", tax_type)
ret = {
@ -196,6 +193,8 @@ class DocType:
if self.doc.name:
self.old_page_name = webnotes.conn.get_value('Item', self.doc.name, 'page_name')
self.validate_is_stock_item()
def check_non_asset_warehouse(self):
if self.doc.is_asset_item == "Yes":
@ -215,6 +214,15 @@ class DocType:
'description' : file and file[0]['description'] or ''
}
return ret
def validate_is_stock_item(self):
if not self.doc.fields.get("__islocal"):
if webnotes.conn.get_value("Item", self.doc.name, "is_stock_item")=="Yes" and \
((not self.doc.is_stock_item) or self.doc.is_stock_item == "No"):
if self.check_if_sle_exists() == "exists":
webnotes.msgprint(self.meta.get_label("is_stock_item") + ": "
+ _("""Cannot change to Yes. Reason: Stock Ledger Entries exist for""")
+ """ "%s" """ % self.doc.name, raise_exception=True)
def check_if_sle_exists(self):
sle = sql("select name from `tabStock Ledger Entry` where item_code = %s and ifnull(is_cancelled, 'No') = 'No'", self.doc.name)
@ -230,8 +238,7 @@ class DocType:
from website.helpers.product import get_parent_item_groups, url_for_website
self.parent_groups = get_parent_item_groups(self.doc.item_group) + [{"name":self.doc.name}]
self.doc.website_image = url_for_website(self.doc.website_image)
self.doc.title = self.doc.item_name == self.doc.name and self.doc.item_name or \
(self.doc.item_name + " [" + self.doc.name + "]")
self.doc.title = self.doc.item_name
if self.doc.slideshow:
from website.helpers.slideshow import get_slideshow

View File

@ -127,4 +127,23 @@ test_records = [
"is_sub_contracted_item": "Yes",
"stock_uom": "_Test UOM"
}],
[{
"doctype": "Item",
"item_code": "_Test Non Stock Item",
"item_name": "_Test Non Stock Item",
"description": "_Test Non Stock Item",
"item_group": "_Test Item Group Desktops",
"is_stock_item": "No",
"is_asset_item": "No",
"has_batch_no": "No",
"has_serial_no": "No",
"is_purchase_item": "Yes",
"is_sales_item": "Yes",
"is_service_item": "No",
"is_sample_item": "No",
"inspection_required": "No",
"is_pro_applicable": "No",
"is_sub_contracted_item": "No",
"stock_uom": "_Test UOM"
}],
]

View File

@ -125,7 +125,7 @@ class DocType(BuyingController):
self.update_raw_materials_supplied("pr_raw_material_details")
self.update_valuation_rate("purchase_receipt_details")
def on_update(self):
if self.doc.rejected_warehouse:
for d in getlist(self.doclist,'purchase_receipt_details'):
@ -146,6 +146,9 @@ class DocType(BuyingController):
self.values = []
for d in getlist(self.doclist, 'purchase_receipt_details'):
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
if not d.warehouse:
continue
ord_qty = 0
pr_qty = flt(d.qty) * flt(d.conversion_factor)

View File

@ -19,7 +19,6 @@ wn.provide("erpnext.stock");
erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
onload_post_render: function() {
this._super();
if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no)
&& !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) {
// if production order / bom is mentioned, get items
@ -28,7 +27,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
},
refresh: function() {
this._super();
erpnext.hide_naming_series();
this.toggle_related_fields(this.frm.doc);
this.toggle_enable_bom();
if (this.frm.doc.docstatus==1) {

View File

@ -29,9 +29,9 @@ import json
sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
from controllers.accounts_controller import AccountsController
class DocType(TransactionBase):
class DocType(AccountsController):
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
@ -39,11 +39,11 @@ class DocType(TransactionBase):
def validate(self):
self.validate_purpose()
self.validate_serial_nos()
pro_obj = self.doc.production_order and \
get_obj('Production Order', self.doc.production_order) or None
self.validate_item()
self.validate_warehouse(pro_obj)
self.validate_production_order(pro_obj)
self.get_stock_and_rate()
@ -51,20 +51,19 @@ class DocType(TransactionBase):
self.validate_bom()
self.validate_finished_goods()
self.validate_return_reference_doc()
self.validate_with_material_request()
def on_submit(self):
self.update_serial_no(1)
self.update_stock_ledger(0)
# update Production Order
self.update_production_order(1)
self.make_gl_entries()
def on_cancel(self):
self.update_serial_no(0)
self.update_stock_ledger(1)
# update Production Order
self.update_production_order(0)
self.make_gl_entries()
def validate_purpose(self):
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer",
@ -78,6 +77,12 @@ class DocType(TransactionBase):
sl_obj.scrub_serial_nos(self)
sl_obj.validate_serial_no(self, 'mtn_details')
def validate_item(self):
for item in self.doclist.get({"parentfield": "mtn_details"}):
if item.item_code not in self.stock_items:
msgprint(_("""Only Stock Items are allowed for Stock Entry"""),
raise_exception=True)
def validate_warehouse(self, pro_obj):
"""perform various (sometimes conditional) validations on warehouse"""
@ -159,6 +164,47 @@ class DocType(TransactionBase):
elif self.doc.purpose != "Material Transfer":
self.doc.production_order = None
def make_gl_entries(self):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
return
abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
stock_in_hand_account = self.get_stock_in_hand_account()
total_valuation_amount = self.get_total_valuation_amount()
if total_valuation_amount:
gl_entries = [
# debit stock in hand account
self.get_gl_dict({
"account": stock_in_hand_account,
"against": "Stock Adjustment - %s" % abbr,
"debit": total_valuation_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock",
}, self.doc.docstatus == 2),
# debit stock received but not billed account
self.get_gl_dict({
"account": "Stock Adjustment - %s" % abbr,
"against": stock_in_hand_account,
"credit": total_valuation_amount,
"cost_center": "Auto Inventory Accounting - %s" % abbr,
"remarks": self.doc.remarks or "Accounting Entry for Stock",
}, self.doc.docstatus == 2),
]
from accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
def get_total_valuation_amount(self):
total_valuation_amount = 0
for item in self.doclist.get({"parentfield": "mtn_details"}):
if item.t_warehouse and not item.s_warehouse:
total_valuation_amount += flt(item.incoming_rate) * flt(item.transfer_qty)
if item.s_warehouse and not item.t_warehouse:
total_valuation_amount -= flt(item.incoming_rate) * flt(item.transfer_qty)
return total_valuation_amount
def get_stock_and_rate(self):
"""get stock and incoming rate on posting date"""
for d in getlist(self.doclist, 'mtn_details'):

View File

@ -21,6 +21,143 @@ class TestStockEntry(unittest.TestCase):
where item_code='_Test Item'""")
self.assertTrue(mr_name)
def test_material_receipt_gl_entry(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
mr = webnotes.bean(copy=test_records[0])
mr.insert()
mr.submit()
stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company",
"stock_in_hand_account")
self.check_stock_ledger_entries("Stock Entry", mr.doc.name,
[["_Test Item", "_Test Warehouse", 50.0]])
self.check_gl_entries("Stock Entry", mr.doc.name,
sorted([
[stock_in_hand_account, 5000.0, 0.0],
["Stock Adjustment - _TC", 0.0, 5000.0]
])
)
mr.cancel()
self.check_stock_ledger_entries("Stock Entry", mr.doc.name,
sorted([["_Test Item", "_Test Warehouse", 50.0],
["_Test Item", "_Test Warehouse", -50.0]]))
self.check_gl_entries("Stock Entry", mr.doc.name,
sorted([
[stock_in_hand_account, 5000.0, 0.0],
["Stock Adjustment - _TC", 0.0, 5000.0],
[stock_in_hand_account, 0.0, 5000.0],
["Stock Adjustment - _TC", 5000.0, 0.0]
])
)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_material_issue_gl_entry(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
mr = webnotes.bean(copy=test_records[0])
mr.insert()
mr.submit()
mi = webnotes.bean(copy=test_records[1])
mi.insert()
mi.submit()
stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company",
"stock_in_hand_account")
self.check_stock_ledger_entries("Stock Entry", mi.doc.name,
[["_Test Item", "_Test Warehouse", -40.0]])
self.check_gl_entries("Stock Entry", mi.doc.name,
sorted([
[stock_in_hand_account, 0.0, 4000.0],
["Stock Adjustment - _TC", 4000.0, 0.0]
])
)
mi.cancel()
self.check_stock_ledger_entries("Stock Entry", mi.doc.name,
sorted([["_Test Item", "_Test Warehouse", -40.0],
["_Test Item", "_Test Warehouse", 40.0]]))
self.check_gl_entries("Stock Entry", mi.doc.name,
sorted([
[stock_in_hand_account, 0.0, 4000.0],
["Stock Adjustment - _TC", 4000.0, 0.0],
[stock_in_hand_account, 4000.0, 0.0],
["Stock Adjustment - _TC", 0.0, 4000.0],
])
)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_material_transfer_gl_entry(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
mr = webnotes.bean(copy=test_records[0])
mr.insert()
mr.submit()
mtn = webnotes.bean(copy=test_records[2])
mtn.insert()
mtn.submit()
self.check_stock_ledger_entries("Stock Entry", mtn.doc.name,
[["_Test Item", "_Test Warehouse", -45.0], ["_Test Item", "_Test Warehouse 1", 45.0]])
# no gl entry
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
where voucher_type = 'Stock Entry' and voucher_no=%s""", mtn.doc.name)
self.assertFalse(gl_entries)
mtn.cancel()
self.check_stock_ledger_entries("Stock Entry", mtn.doc.name,
sorted([["_Test Item", "_Test Warehouse", 45.0],
["_Test Item", "_Test Warehouse 1", -45.0],
["_Test Item", "_Test Warehouse", -45.0],
["_Test Item", "_Test Warehouse 1", 45.0]]))
# no gl entry
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
where voucher_type = 'Stock Entry' and voucher_no=%s""", mtn.doc.name)
self.assertFalse(gl_entries)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle):
# check stock ledger entries
sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` where voucher_type = %s
and voucher_no = %s order by item_code, warehouse, actual_qty""",
(voucher_type, voucher_no), as_dict=1)
self.assertTrue(sle)
for i, sle in enumerate(sle):
self.assertEquals(expected_sle[i][0], sle.item_code)
self.assertEquals(expected_sle[i][1], sle.warehouse)
self.assertEquals(expected_sle[i][2], sle.actual_qty)
def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries):
# check gl entries
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account asc, debit asc""", (voucher_type, voucher_no), as_dict=1)
self.assertTrue(gl_entries)
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
test_records = [
[
@ -29,7 +166,8 @@ test_records = [
"doctype": "Stock Entry",
"posting_date": "2013-01-25",
"posting_time": "17:14:24",
"purpose": "Material Receipt"
"purpose": "Material Receipt",
"fiscal_year": "_Test Fiscal Year 2013",
},
{
"conversion_factor": 1.0,
@ -50,7 +188,8 @@ test_records = [
"doctype": "Stock Entry",
"posting_date": "2013-01-25",
"posting_time": "17:15",
"purpose": "Material Issue"
"purpose": "Material Issue",
"fiscal_year": "_Test Fiscal Year 2013",
},
{
"conversion_factor": 1.0,
@ -71,12 +210,13 @@ test_records = [
"doctype": "Stock Entry",
"posting_date": "2013-01-25",
"posting_time": "17:14:24",
"purpose": "Material Transfer"
"purpose": "Material Transfer",
"fiscal_year": "_Test Fiscal Year 2013",
},
{
"conversion_factor": 1.0,
"doctype": "Stock Entry Detail",
"item_code": "_Test Item Home Desktop 100",
"item_code": "_Test Item",
"parentfield": "mtn_details",
"incoming_rate": 100,
"qty": 45.0,
@ -85,19 +225,6 @@ test_records = [
"uom": "_Test UOM",
"s_warehouse": "_Test Warehouse",
"t_warehouse": "_Test Warehouse 1",
},
{
"conversion_factor": 1.0,
"doctype": "Stock Entry Detail",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "mtn_details",
"qty": 45.0,
"incoming_rate": 100,
"stock_uom": "_Test UOM",
"transfer_qty": 45.0,
"uom": "_Test UOM",
"s_warehouse": "_Test Warehouse",
"t_warehouse": "_Test Warehouse 1",
}
]
]

View File

@ -17,7 +17,7 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, cstr, flt, nowdate, cint
from webnotes.utils import add_days, cstr, flt, nowdate, cint, now
from webnotes.model.doc import Document
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
@ -49,7 +49,7 @@ class DocType:
serial_nos = get_valid_serial_nos(d.serial_no)
for s in serial_nos:
s = s.strip()
sr_war = sql("select warehouse,name from `tabSerial No` where name = '%s'" % (s))
sr_war = webnotes.conn.sql("select warehouse,name from `tabSerial No` where name = '%s'" % (s))
if not sr_war:
msgprint("Serial No %s does not exists"%s, raise_exception = 1)
elif not sr_war[0][0]:
@ -81,7 +81,7 @@ class DocType:
def set_pur_serial_no_values(self, obj, serial_no, d, s, new_rec, rejected=None):
item_details = sql("""select item_group, warranty_period
item_details = webnotes.conn.sql("""select item_group, warranty_period
from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or
end_of_life = '0000-00-00' or end_of_life > now()) """ %(d.item_code), as_dict=1)
@ -112,7 +112,7 @@ class DocType:
def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = '', rejected=None):
exists = sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
exists = webnotes.conn.sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
if is_submit:
if exists and exists[0][2] != 2 and purpose not in ['Material Transfer', 'Sales Return']:
msgprint("Serial No: %s already %s" % (serial_no, exists and exists[0][1]), raise_exception = 1)
@ -126,15 +126,15 @@ class DocType:
if exists and exists[0][1] == 'Delivered' and exists[0][2] != 2:
msgprint("Serial No: %s is already delivered, you can not cancel the document." % serial_no, raise_exception=1)
elif purpose == 'Material Transfer':
sql("update `tabSerial No` set status = 'In Store', purchase_document_type = '', purchase_document_no = '', warehouse = '%s' where name = '%s'" % (d.s_warehouse, serial_no))
webnotes.conn.sql("update `tabSerial No` set status = 'In Store', purchase_document_type = '', purchase_document_no = '', warehouse = '%s' where name = '%s'" % (d.s_warehouse, serial_no))
elif purpose == 'Sales Return':
sql("update `tabSerial No` set status = 'Delivered', purchase_document_type = '', purchase_document_no = '' where name = '%s'" % serial_no)
webnotes.conn.sql("update `tabSerial No` set status = 'Delivered', purchase_document_type = '', purchase_document_no = '' where name = '%s'" % serial_no)
else:
sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no)
webnotes.conn.sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no)
def check_serial_no_exists(self, serial_no, item_code):
chk = sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1)
chk = webnotes.conn.sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1)
if not chk:
msgprint("Serial No: %s does not exists in the system" % serial_no, raise_exception=1)
elif chk and chk[0]['item_code'] != item_code:
@ -169,7 +169,7 @@ class DocType:
self.check_serial_no_exists(serial_no, d.item_code)
self.set_delivery_serial_no_values(obj, serial_no)
else:
sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no))
webnotes.conn.sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no))
def update_serial_record(self, obj, fname, is_submit = 1, is_incoming = 0):
@ -202,8 +202,10 @@ class DocType:
if v.get('is_cancelled') == 'Yes':
v['actual_qty'] = -flt(v['actual_qty'])
# cancel matching entry
sql("update `tabStock Ledger Entry` set is_cancelled='Yes' where voucher_no=%s \
and voucher_type=%s", (v['voucher_no'], v['voucher_type']))
webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
modified=%s, modified_by=%s
where voucher_no=%s and voucher_type=%s""",
(now(), webnotes.session.user, v['voucher_no'], v['voucher_type']))
if v.get("actual_qty"):
sle_id = self.make_entry(v)
@ -230,5 +232,5 @@ class DocType:
"""
Repost everything!
"""
for wh in sql("select name from tabWarehouse"):
for wh in webnotes.conn.sql("select name from tabWarehouse"):
get_obj('Warehouse', wh[0]).repost_stock()

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-01-10 16:34:30",
"creation": "2013-03-07 18:50:32",
"docstatus": 0,
"modified": "2013-02-04 11:35:53",
"modified": "2013-03-11 17:58:45",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -21,7 +21,8 @@
"name": "__common__",
"parent": "Warehouse",
"parentfield": "fields",
"parenttype": "DocType"
"parenttype": "DocType",
"read_only": 0
},
{
"doctype": "DocPerm",
@ -190,7 +191,7 @@
"permlevel": 0
},
{
"description": "This feature is for merging duplicate warehouses. It will replace all the links of this warehouse by \"Merge With\" warehouse. After merging you can delete this warehouse, as stock level for this warehouse will be zero.",
"description": "This feature is for merging duplicate warehouses. It will replace all the links of this warehouse by \"Merge Into\" warehouse. After merging you can delete this warehouse, as stock level for this warehouse will be zero.",
"doctype": "DocField",
"fieldname": "merge_warehouses_section",
"fieldtype": "Section Break",
@ -201,7 +202,7 @@
"doctype": "DocField",
"fieldname": "merge_with",
"fieldtype": "Link",
"label": "Merge With",
"label": "Merge Into",
"options": "Warehouse",
"permlevel": 2
},
@ -221,24 +222,6 @@
"role": "Material Master Manager",
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 0,
"role": "Material User",
"write": 0
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 2,
"role": "Material User",
"write": 0
},
{
"cancel": 1,
"create": 1,
@ -248,6 +231,26 @@
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 0,
"role": "Material Manager",
"write": 0
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 0,
"role": "Material User",
"write": 0
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 2,

View File

@ -99,6 +99,7 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({
var data = wn.report_dump.data["Stock Ledger Entry"];
this.item_warehouse = {};
this.serialized_buying_rates = this.get_serialized_buying_rates();
for(var i=0, j=data.length; i<j; i++) {
var sl = data[i];

View File

@ -155,6 +155,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({
// initialize warehouse-item map
this.item_warehouse = {};
this.serialized_buying_rates = this.get_serialized_buying_rates();
var from_datetime = dateutil.str_to_obj(me.from_date + " 00:00:00");
var to_datetime = dateutil.str_to_obj(me.to_date + " 23:59:59");

View File

@ -36,7 +36,6 @@ def update_entries_after(args, verbose=1):
}
"""
previous_sle = get_sle_before_datetime(args)
qty_after_transaction = flt(previous_sle.get("qty_after_transaction"))
valuation_rate = flt(previous_sle.get("valuation_rate"))
stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
@ -214,7 +213,6 @@ def get_moving_average_values(qty_after_transaction, sle, valuation_rate):
def get_fifo_values(qty_after_transaction, sle, stock_queue):
incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty)
if not stock_queue:
stock_queue.append([0, 0])

View File

@ -164,34 +164,37 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters):
wlist.append([w])
return wlist
def get_buying_amount(item_code, warehouse, qty, voucher_no, voucher_detail_no,
def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no,
stock_ledger_entries, item_sales_bom):
if item_sales_bom.get(item_code):
# sales bom item
buying_amount = 0.0
for bom_item in item_sales_bom[item_code]:
buying_amount += _get_buying_amount(voucher_no, "[** No Item Row **]",
item_code, warehouse, bom_item.qty * qty, stock_ledger_entries)
buying_amount += _get_buying_amount(voucher_type, voucher_no, "[** No Item Row **]",
bom_item.item_code, warehouse, bom_item.qty * qty, stock_ledger_entries)
return buying_amount
else:
# doesn't have sales bom
return _get_buying_amount(voucher_no, voucher_detail_no, item_code, warehouse, qty,
stock_ledger_entries)
return _get_buying_amount(voucher_type, voucher_no, voucher_detail_no,
item_code, warehouse, qty, stock_ledger_entries)
def _get_buying_amount(voucher_no, item_row, item_code, warehouse, qty, stock_ledger_entries):
def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse, qty,
stock_ledger_entries):
for i, sle in enumerate(stock_ledger_entries):
if sle.voucher_type == "Delivery Note" and sle.voucher_no == voucher_no:
if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \
len(stock_ledger_entries) > i+1:
if (sle.voucher_detail_no == item_row) or \
(sle.item_code == item_code and sle.warehouse == warehouse and \
abs(flt(sle.qty)) == qty):
buying_amount = flt(stock_ledger_entries[i+1].stock_value) - flt(sle.stock_value)
buying_amount = flt(stock_ledger_entries[i+1].stock_value) - \
flt(sle.stock_value)
return buying_amount
return 0.0
def get_sales_bom():
item_sales_bom = {}
# for r in webnotes.conn.sql("""select parent_item, item_code, qty, warehouse, voucher_detail_no
# from `tabDelivery Note Packing Item` where docstatus = 1""", as_dict=1):
for r in webnotes.conn.sql("""select parent, item_code, qty from `tabSales BOM Item`""",
as_dict=1):
item_sales_bom.setdefault(r.parent, []).append(r)

View File

@ -20,16 +20,14 @@ import webnotes
def delete_transactions():
print "Deleting transactions..."
trans = ['Timesheet','Task','Support Ticket','Stock Reconciliation', 'Stock Ledger Entry', \
'Stock Entry','Sales Order','Salary Slip','Sales Invoice','Quotation', 'Quality Inspection', \
'Purchase Receipt','Purchase Order','Production Order', 'POS Setting','Period Closing Voucher', \
'Purchase Invoice','Maintenance Visit','Maintenance Schedule','Leave Application', \
'Leave Allocation', 'Lead', 'Journal Voucher', 'Installation Note','Material Request', \
'GL Entry','Expense Claim','Opportunity','Delivery Note','Customer Issue','Bin', \
'Authorization Rule','Attendance', 'C-Form', 'Form 16A', 'Lease Agreement', \
'Lease Installment', 'TDS Payment', 'TDS Return Acknowledgement', 'Appraisal', \
'Installation Note', 'Communication'
]
trans = ['Timesheet', 'Task', 'Support Ticket', 'Stock Reconciliation', 'Stock Ledger Entry',
'Stock Entry', 'Sales Order', 'Salary Slip','Sales Invoice', 'Quotation',
'Quality Inspection', 'Purchase Receipt', 'Purchase Order', 'Production Order',
'POS Setting', 'Period Closing Voucher', 'Purchase Invoice', 'Maintenance Visit',
'Maintenance Schedule', 'Leave Application', 'Leave Allocation', 'Lead', 'Journal Voucher',
'Installation Note', 'Material Request', 'GL Entry', 'Expense Claim', 'Opportunity',
'Delivery Note', 'Customer Issue', 'Bin', 'Authorization Rule', 'Attendance', 'C-Form',
'Appraisal', 'Installation Note', 'Communication']
for d in trans:
for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d):
webnotes.conn.sql("delete from `tab%s`" % (t))
@ -41,55 +39,55 @@ def delete_transactions():
def delete_masters():
print "Deleting masters...."
masters = {
'Workstation':['Default Workstation'],
'Warehouse Type':['Default Warehouse Type', 'Fixed Asset', 'Rejected', 'Reserved',
'Workstation': ['Default Workstation'],
'Warehouse Type': ['Default Warehouse Type', 'Fixed Asset', 'Rejected', 'Reserved',
'Sample', 'Stores', 'WIP Warehouse'],
'Warehouse':['Default Warehouse'],
'UOM':['Kg', 'Mtr', 'Box', 'Ltr', 'Nos', 'Ft', 'Pair', 'Set'],
'Territory':['All Territories', 'Default Territory'],
'Terms and Conditions':'',
'Tag':'',
'Supplier Type':['Default Supplier Type'],
'Supplier':'',
'Serial No':'',
'Sales Person':['All Sales Persons'],
'Sales Partner':'',
'Sales BOM':'',
'Salary Structure':'',
'Purchase Taxes and Charges Master':'',
'Project':'',
'Print Heading':'',
'Price List':['Default Price List'],
'Sales Taxes and Charges Master':'',
'Letter Head':'',
'Leave Type':['Leave Without Pay', 'Privilege Leave', 'Casual Leave', 'PL', 'CL', 'LWP',
'Warehouse': ['Default Warehouse'],
'UOM': ['Kg', 'Mtr', 'Box', 'Ltr', 'Nos', 'Ft', 'Pair', 'Set'],
'Territory': ['All Territories', 'Default Territory'],
'Terms and Conditions': '',
'Tag': '',
'Supplier Type': ['Default Supplier Type'],
'Supplier': '',
'Serial No': '',
'Sales Person': ['All Sales Persons'],
'Sales Partner': '',
'Sales BOM': '',
'Salary Structure': '',
'Purchase Taxes and Charges Master': '',
'Project': '',
'Print Heading': '',
'Price List': ['Default Price List'],
'Sales Taxes and Charges Master': '',
'Letter Head': '',
'Leave Type': ['Leave Without Pay', 'Privilege Leave', 'Casual Leave', 'PL', 'CL', 'LWP',
'Compensatory Off', 'Sick Leave'],
'Appraisal Template':'',
'Item Group':['All Item Groups', 'Default'],
'Item':'',
'Holiday List':'',
'Grade':'',
'Feed':'',
'Expense Claim Type':['Travel', 'Medical', 'Calls', 'Food', 'Others'],
'Event':'',
'Employment Type':'',
'Employee':'',
'Earning Type':['Basic', 'Conveyance', 'House Rent Allowance', 'Dearness Allowance',
'Appraisal Template': '',
'Item Group': ['All Item Groups', 'Default'],
'Item': '',
'Holiday List': '',
'Grade': '',
'Feed': '',
'Expense Claim Type': ['Travel', 'Medical', 'Calls', 'Food', 'Others'],
'Event': '',
'Employment Type': '',
'Employee': '',
'Earning Type': ['Basic', 'Conveyance', 'House Rent Allowance', 'Dearness Allowance',
'Medical Allowance', 'Telephone'],
'Designation':'',
'Department':'',
'Deduction Type':['Income Tax', 'Professional Tax', 'Provident Fund', 'Leave Deduction'],
'Customer Group':['All Customer Groups', 'Default Customer Group'],
'Customer':'',
'Cost Center':'',
'Contact':'',
'Campaign':'',
'Budget Distribution':'',
'Brand':'',
'Branch':'',
'Batch':'',
'Appraisal':'',
'Account':'',
'Designation': '',
'Department': '',
'Deduction Type': ['Income Tax', 'Professional Tax', 'Provident Fund', 'Leave Deduction'],
'Customer Group': ['All Customer Groups', 'Default Customer Group'],
'Customer': '',
'Cost Center': '',
'Contact': '',
'Campaign': '',
'Budget Distribution': '',
'Brand': '',
'Branch': '',
'Batch': '',
'Appraisal': '',
'Account': '',
'BOM': ''
}
for d in masters.keys():
@ -115,40 +113,40 @@ def reset_all_series():
def reset_transaction_series():
webnotes.conn.sql("""update tabSeries set current = 0 where name in
('JV', 'INV', 'BILL', 'SO', 'DN', 'PO', 'LEAD', 'ENQUIRY', 'ENQ', 'CI',
'IN', 'PS', 'IDT', 'QAI', 'QTN', 'STE', 'SQTN', 'SUP', 'TDSP', 'SR',
'IN', 'PS', 'IDT', 'QAI', 'QTN', 'STE', 'SQTN', 'SUP', 'SR',
'POS', 'LAP', 'LAL', 'EXP')""")
print "Series updated"
def delete_main_masters():
main_masters = ['Fiscal Year','Company', 'DefaultValue']
main_masters = ['Fiscal Year', 'Company', 'DefaultValue']
for d in main_masters:
for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d):
webnotes.conn.sql("delete from `tab%s`" % (t))
webnotes.conn.sql("delete from `tab%s`" % (d))
print "Deleted " + d
def reset_global_defaults():
flds = {
'default_company': '',
'default_currency': '',
'current_fiscal_year': '',
'default_company': None,
'default_currency': None,
'current_fiscal_year': None,
'date_format': 'dd-mm-yyyy',
'sms_sender_name': '',
'sms_sender_name': None,
'default_item_group': 'Default',
'default_stock_uom': 'Nos',
'default_valuation_method': 'FIFO',
'default_warehouse_type': 'Default Warehouse Type',
'tolerance': '',
'acc_frozen_upto': '',
'bde_auth_role': '',
'credit_controller': '',
'tolerance': None,
'acc_frozen_upto': None,
'bde_auth_role': None,
'credit_controller': None,
'default_customer_group': 'Default Customer Group',
'default_territory': 'Default',
'default_price_list': 'Standard',
'default_supplier_type': 'Default Supplier Type'
'default_supplier_type': 'Default Supplier Type',
'hide_currency_symbol': None,
'default_price_list_currency': None,
}
from webnotes.model.code import get_obj

View File

@ -1,17 +1,12 @@
div.outer {
-moz-box-shadow: 0px 0px 3px rgba(0,0,0,0.9);
-webkit-box-shadow: 0px 0px 3px rgba(0,0,0,0.9);
box-shadow: 0px 0px 3px rgba(0,0,0,0.9);
background-color: #fff;
border-radius: 5px;
padding: 20px;
margin: 30px -20px 10px -20px;
padding: 30px;
margin: 30px -30px 10px -30px;
min-height: 400px;
overflow: hidden;
}
.outer .navbar {
margin: -20px -20px 10px -20px;
margin: -30px -30px 10px -30px;
}
footer {
@ -24,6 +19,8 @@ footer {
border: 0px;
border-bottom: 1px solid #ddd;
border-radius: 0px;
padding-right: 30px;
padding-left: 30px;
}
p, li {
@ -98,6 +95,18 @@ p, li {
width: 30px;
}
.avatar-medium {
margin-right: 5px;
width: 48px;
height: 48px;
border-radius: 48px;
-moz-border-radius: 48px;
-webkit-border-radius: 48px;
}
.avatar-medium img {
width: 48px;
}
.avatar-large {
margin-right: 10px;
width: 72px;
@ -121,5 +130,3 @@ p, li {
.avatar-x-large img {
width: 100px;
}
/* */

View File

@ -7,16 +7,16 @@ from website.utils import url_for_website
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def onload(self):
"""load employee"""
emp_list = []
for d in self.doclist.get({"doctype":"About Us Team Member"}):
emp = webnotes.doc("Employee", d.employee)
emp.image = url_for_website(emp.image)
emp_list.append(emp)
self.doclist += emp_list
def on_update(self):
from website.utils import clear_cache
clear_cache("about")
clear_cache("about")
def get_args():
obj = webnotes.get_obj("About Us Settings")
for d in obj.doclist.get({"doctype":"About Us Team Member"}):
if not "/" in d.image_link:
d.image_link = "files/" + d.image_link
return {
"obj": obj
}

View File

@ -1,12 +1,13 @@
[
{
"creation": "2013-01-10 16:34:32",
"creation": "2013-03-07 15:53:15",
"docstatus": 0,
"modified": "2013-01-22 14:12:16",
"modified": "2013-03-12 14:48:34",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"description": "Settings for the About Us Page",
"doctype": "DocType",
"document_type": "Master",
@ -31,7 +32,7 @@
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"report": 1,
"report": 0,
"role": "Website Manager",
"submit": 0,
"write": 1
@ -45,7 +46,7 @@
"fieldname": "help",
"fieldtype": "HTML",
"label": "Help",
"options": "<div class=\"alert\">Link for About Us Page is \"about.html\"</div>"
"options": "<div class=\"alert\">Link for About Us Page is \"/about\"</div>"
},
{
"description": "Introduce your company to the website visitor.",
@ -101,6 +102,15 @@
"fieldtype": "Text Editor",
"label": "Footer"
},
{
"doctype": "DocField",
"fieldname": "file_list",
"fieldtype": "Text",
"hidden": 1,
"label": "File List",
"no_copy": 1,
"print_hide": 1
},
{
"doctype": "DocPerm"
}

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-02-22 01:28:07",
"creation": "2013-03-07 11:55:11",
"docstatus": 0,
"modified": "2013-03-07 07:03:18",
"modified": "2013-03-12 13:51:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -14,23 +14,38 @@
},
{
"doctype": "DocField",
"fieldname": "employee",
"fieldtype": "Link",
"label": "Employee",
"name": "__common__",
"options": "Employee",
"parent": "About Us Team Member",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"print_width": "300px",
"width": "300px"
"permlevel": 0
},
{
"doctype": "DocType",
"name": "About Us Team Member"
},
{
"doctype": "DocField"
"doctype": "DocField",
"fieldname": "full_name",
"fieldtype": "Data",
"label": "Full Name",
"reqd": 1,
"width": "150px"
},
{
"doctype": "DocField",
"fieldname": "image_link",
"fieldtype": "Select",
"label": "Image Link",
"options": "attach_files:",
"width": "150px"
},
{
"doctype": "DocField",
"fieldname": "bio",
"fieldtype": "Small Text",
"label": "Bio",
"reqd": 1,
"width": "200px"
}
]

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,12 +0,0 @@
[
"Website",
"Content",
"Title",
"Blog Intro",
"Page Name",
"Blog",
"Email Sent",
"File List",
"Published",
"Description for listing page, in plain text, only a couple of lines."
]

View File

@ -1,10 +0,0 @@
{
"Blog": "\u0628\u0644\u0648\u0642",
"Content": "\u0645\u062d\u062a\u0648\u0649",
"Email Sent": "\u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a",
"File List": "\u0645\u0644\u0641 \u0642\u0627\u0626\u0645\u0629",
"Page Name": "\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0633\u0645",
"Published": "\u0646\u0634\u0631\u062a",
"Title": "\u0644\u0642\u0628",
"Website": "\u0627\u0644\u0645\u0648\u0642\u0639"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Inhalt",
"Email Sent": "E-Mail gesendet",
"File List": "Dateiliste",
"Page Name": "Page Name",
"Published": "Ver\u00f6ffentlicht",
"Title": "Titel",
"Website": "Webseite"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Contenido",
"Email Sent": "Correo electr\u00f3nico enviado",
"File List": "Lista de archivos",
"Page Name": "Nombre p\u00e1gina",
"Published": "Publicado",
"Title": "T\u00edtulo",
"Website": "Sitio web"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Teneur",
"Email Sent": "Courriel a \u00e9t\u00e9 envoy\u00e9",
"File List": "Liste des fichiers",
"Page Name": "Nom de la page",
"Published": "Publi\u00e9",
"Title": "Titre",
"Website": "Site Web"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "\u092c\u094d\u0932\u0949\u0917",
"Content": "\u0938\u093e\u092e\u0917\u094d\u0930\u0940",
"Email Sent": "\u0908\u092e\u0947\u0932 \u092d\u0947\u091c\u093e \u0917\u092f\u093e",
"File List": "\u092b\u093c\u093e\u0907\u0932 \u0938\u0942\u091a\u0940",
"Page Name": "\u092a\u0947\u091c \u0915\u093e \u0928\u093e\u092e",
"Published": "\u092a\u094d\u0930\u0915\u093e\u0936\u093f\u0924",
"Title": "\u0936\u0940\u0930\u094d\u0937\u0915",
"Website": "\u0935\u0947\u092c\u0938\u093e\u0907\u091f"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Sadr\u017eaj",
"Email Sent": "E-mail poslan",
"File List": "Popis datoteka",
"Page Name": "Stranica Ime",
"Published": "Objavljen",
"Title": "Naslov",
"Website": "Website"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Inhoud",
"Email Sent": "E-mail verzonden",
"File List": "File List",
"Page Name": "Page Name",
"Published": "Gepubliceerd",
"Title": "Titel",
"Website": "Website"
}

View File

@ -1,12 +0,0 @@
{
"Blog": "Blog",
"Blog Intro": "Blog Intro",
"Content": "Conte\u00fado",
"Description for listing page, in plain text, only a couple of lines.": "Descri\u00e7\u00e3o p\u00e1gina de listagem, em texto simples, apenas um par de linhas.",
"Email Sent": "E-mail enviado",
"File List": "Lista de Arquivos",
"Page Name": "Nome da P\u00e1gina",
"Published": "Publicado",
"Title": "T\u00edtulo",
"Website": "Site"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "Blog",
"Content": "Conte\u00fado",
"Email Sent": "E-mail enviado",
"File List": "Lista de Arquivos",
"Page Name": "Nome da P\u00e1gina",
"Published": "Publicado",
"Title": "T\u00edtulo",
"Website": "Site"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "\u0411\u043b\u043e\u0433",
"Content": "\u0421\u0430\u0434\u0440\u0436\u0438\u043d\u0430",
"Email Sent": "\u0415\u043c\u0430\u0438\u043b \u0421\u0435\u043d\u0442",
"File List": "\u0424\u0438\u043b\u0435 \u041b\u0438\u0441\u0442",
"Page Name": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0418\u043c\u0435",
"Published": "\u041e\u0431\u0458\u0430\u0432\u0459\u0435\u043d",
"Title": "\u041d\u0430\u0441\u043b\u043e\u0432",
"Website": "\u0412\u0435\u0431\u0441\u0430\u0458\u0442"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "\u0bb5\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0ba4\u0bbf\u0bb5\u0bc1",
"Content": "\u0b89\u0bb3\u0bcd\u0bb3\u0b9f\u0b95\u0bcd\u0b95\u0bae\u0bcd",
"Email Sent": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
"File List": "\u0b95\u0bc7\u0bbe\u0baa\u0bcd\u0baa\u0bc1 \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd",
"Page Name": "\u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd \u0baa\u0bc6\u0baf\u0bb0\u0bcd",
"Published": "\u0bb5\u0bc6\u0bb3\u0bbf\u0baf\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f",
"Title": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
"Website": "\u0b87\u0ba3\u0bc8\u0baf\u0ba4\u0bb3\u0bae\u0bcd"
}

View File

@ -1,10 +0,0 @@
{
"Blog": "\u0e1a\u0e25\u0e47\u0e2d\u0e01",
"Content": "\u0e40\u0e19\u0e37\u0e49\u0e2d\u0e2b\u0e32",
"Email Sent": "\u0e2d\u0e35\u0e40\u0e21\u0e25\u0e17\u0e35\u0e48\u0e2a\u0e48\u0e07",
"File List": "\u0e23\u0e32\u0e22\u0e0a\u0e37\u0e48\u0e2d\u0e44\u0e1f\u0e25\u0e4c",
"Page Name": "\u0e0a\u0e37\u0e48\u0e2d\u0e40\u0e1e\u0e08",
"Published": "\u0e40\u0e1c\u0e22\u0e41\u0e1e\u0e23\u0e48",
"Title": "\u0e0a\u0e37\u0e48\u0e2d\u0e40\u0e23\u0e37\u0e48\u0e2d\u0e07",
"Website": "\u0e40\u0e27\u0e47\u0e1a\u0e44\u0e0b\u0e15\u0e4c"
}

View File

@ -0,0 +1,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def on_update(self):
# for blog footer
from website.utils import clear_cache
clear_cache()

View File

@ -0,0 +1,51 @@
[
{
"creation": "2013-03-08 09:41:11",
"docstatus": 0,
"modified": "2013-03-08 09:41:11",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"autoname": "field:category_name",
"doctype": "DocType",
"document_type": "Master",
"module": "Website",
"name": "__common__"
},
{
"doctype": "DocField",
"fieldname": "category_name",
"fieldtype": "Data",
"label": "Category Name",
"name": "__common__",
"parent": "Blog Category",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"reqd": 1
},
{
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Blog Category",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"role": "Website Manager",
"write": 1
},
{
"doctype": "DocType",
"name": "Blog Category"
},
{
"doctype": "DocField"
},
{
"doctype": "DocPerm"
}
]

View File

View File

@ -18,6 +18,7 @@ from __future__ import unicode_literals
import webnotes
import website.utils
from webnotes import _
class DocType:
def __init__(self, d, dl):
@ -27,9 +28,18 @@ class DocType:
from website.utils import page_name
self.doc.name = page_name(self.doc.title)
def validate(self):
if self.doc.blog_intro:
self.doc.blog_intro = self.doc.blog_intro[:140]
# update posts
webnotes.conn.sql("""update tabBlogger set posts=(select count(*) from `tabBlog Post`
where ifnull(blogger,'')=tabBlogger.name)
where name=%s""", self.doc.blogger)
def on_update(self):
from website.utils import update_page_name
update_page_name(self.doc, self.doc.title)
website.utils.update_page_name(self.doc, self.doc.title)
website.utils.delete_page_cache("writers")
def send_emails(self):
"""send emails to subscribers"""
@ -40,8 +50,8 @@ class DocType:
import webnotes.utils
# get leads that are subscribed to the blog
recipients = [e[0] for e in webnotes.conn.sql("""select distinct email_id from tabLead where
ifnull(blog_subscriber,0)=1""")]
recipients = [e[0] for e in webnotes.conn.sql("""select distinct email_id from
tabLead where ifnull(blog_subscriber,0)=1""")]
# make heading as link
content = '<h2><a href="%s/%s.html">%s</a></h2>\n\n%s' % (webnotes.utils.get_request_site_address(),
@ -64,12 +74,28 @@ class DocType:
# temp fields
from webnotes.utils import global_date_format, get_fullname
self.doc.full_name = get_fullname(self.doc.owner)
self.doc.updated = global_date_format(self.doc.creation)
self.doc.updated = global_date_format(self.doc.published_on)
self.doc.content_html = self.doc.content
if self.doc.blogger:
self.doc.blogger_info = webnotes.doc("Blogger", self.doc.blogger).fields
if self.doc.blogger_info.avatar and not "/" in self.doc.blogger_info.avatar:
self.doc.blogger_info.avatar = "files/" + self.doc.blogger_info.avatar
self.doc.description = self.doc.blog_intro or self.doc.content[:140]
self.doc.categories = webnotes.conn.sql_list("select name from `tabBlog Category` order by name")
self.doc.texts = {
"comments": _("Comments"),
"first_comment": _("Be the first one to comment"),
"add_comment": _("Add Comment"),
"submit": _("Submit"),
"all_posts_by": _("All posts by"),
}
comment_list = webnotes.conn.sql("""\
select comment, comment_by_fullname, creation
from `tabComment` where comment_doctype="Blog"
from `tabComment` where comment_doctype="Blog Post"
and comment_docname=%s order by creation""", self.doc.name, as_dict=1)
self.doc.comment_list = comment_list or []

View File

@ -1,13 +1,14 @@
[
{
"creation": "2013-01-25 11:35:09",
"creation": "2013-03-08 11:36:50",
"docstatus": 0,
"modified": "2013-02-21 16:54:04",
"modified": "2013-03-11 15:23:21",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"allow_import": 1,
"doctype": "DocType",
"max_attachments": 5,
"module": "Website",
@ -16,7 +17,7 @@
{
"doctype": "DocField",
"name": "__common__",
"parent": "Blog",
"parent": "Blog Post",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
@ -24,7 +25,7 @@
{
"doctype": "DocPerm",
"name": "__common__",
"parent": "Blog",
"parent": "Blog Post",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
@ -34,7 +35,7 @@
},
{
"doctype": "DocType",
"name": "Blog"
"name": "Blog Post"
},
{
"doctype": "DocField",
@ -50,18 +51,50 @@
"label": "Published"
},
{
"description": "Description for listing page, in plain text, only a couple of lines.",
"doctype": "DocField",
"fieldname": "published_on",
"fieldtype": "Date",
"label": "Published On"
},
{
"doctype": "DocField",
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"doctype": "DocField",
"fieldname": "blogger",
"fieldtype": "Link",
"label": "Blogger",
"options": "Blogger",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "blog_category",
"fieldtype": "Link",
"label": "Blog Category",
"options": "Blog Category"
},
{
"doctype": "DocField",
"fieldname": "section_break_5",
"fieldtype": "Section Break"
},
{
"description": "Description for listing page, in plain text, only a couple of lines. (max 140 characters)",
"doctype": "DocField",
"fieldname": "blog_intro",
"fieldtype": "Small Text",
"label": "Blog Intro"
"label": "Blog Intro",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "content",
"fieldtype": "Text Editor",
"label": "Content",
"reqd": 0
"reqd": 1
},
{
"doctype": "DocField",

View File

@ -0,0 +1,8 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@ -0,0 +1,61 @@
[
{
"creation": "2013-03-11 17:48:16",
"docstatus": 0,
"modified": "2013-03-11 17:48:16",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"description": "Blog Settings",
"doctype": "DocType",
"issingle": 1,
"module": "Website",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Blog Settings",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Blog Settings",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"role": "Website Manager",
"write": 1
},
{
"doctype": "DocType",
"name": "Blog Settings"
},
{
"doctype": "DocField",
"fieldname": "blog_title",
"fieldtype": "Data",
"label": "Blog Title"
},
{
"doctype": "DocField",
"fieldname": "blog_introduction",
"fieldtype": "Small Text",
"label": "Blog Introduction"
},
{
"doctype": "DocField",
"fieldname": "writers_introduction",
"fieldtype": "Small Text",
"label": "Writers Introduction"
},
{
"doctype": "DocPerm"
}
]

View File

View File

@ -0,0 +1,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def on_update(self):
"if profile is set, then update all older blogs"
from website.helpers.blog import clear_blog_cache
clear_blog_cache()
if self.doc.profile:
for blog in webnotes.conn.sql_list("""select name from `tabBlog Post` where owner=%s
and ifnull(blogger,'')=''""", self.doc.profile):
b = webnotes.bean("Blog Post", blog)
b.doc.blogger = self.doc.name
b.save()

View File

@ -0,0 +1,102 @@
[
{
"creation": "2013-03-08 11:36:52",
"docstatus": 0,
"modified": "2013-03-11 14:00:37",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"autoname": "field:short_name",
"description": "Profile of a Blogger",
"doctype": "DocType",
"document_type": "Master",
"max_attachments": 1,
"module": "Website",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Blogger",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"doctype": "DocPerm",
"name": "__common__",
"parent": "Blogger",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"write": 1
},
{
"doctype": "DocType",
"name": "Blogger"
},
{
"description": "Will be used in url (usually first name).",
"doctype": "DocField",
"fieldname": "short_name",
"fieldtype": "Data",
"label": "Short Name",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "full_name",
"fieldtype": "Data",
"label": "Full Name",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "profile",
"fieldtype": "Link",
"label": "Profile",
"options": "Profile"
},
{
"doctype": "DocField",
"fieldname": "bio",
"fieldtype": "Small Text",
"label": "Bio"
},
{
"doctype": "DocField",
"fieldname": "avatar",
"fieldtype": "Select",
"label": "Avatar",
"options": "attach_files:"
},
{
"doctype": "DocField",
"fieldname": "posts",
"fieldtype": "Int",
"label": "Posts",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "file_list",
"fieldtype": "Text",
"hidden": 1,
"label": "File List",
"no_copy": 1,
"print_hide": 1
},
{
"create": 1,
"doctype": "DocPerm",
"role": "Website Manager"
},
{
"doctype": "DocPerm",
"match": "owner:profile",
"role": "Blogger"
}
]

View File

@ -1,8 +1,8 @@
[
{
"creation": "2012-12-27 19:04:50",
"creation": "2013-02-21 20:12:42",
"docstatus": 0,
"modified": "2013-02-21 16:49:33",
"modified": "2013-03-12 14:49:01",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -44,7 +44,7 @@
"fieldname": "help",
"fieldtype": "HTML",
"label": "Help",
"options": "<div class=\"alert\">Link for Contact Page is \"contact.html\"</div>"
"options": "<div class=\"alert\">Link for Contact Page is \"/contact\"</div>"
},
{
"description": "Address to be displayed on the Contact Page",

View File

@ -1,3 +1,7 @@
{% if doc.at_import %}
{{ doc.at_import }}
{% endif %}
body {
{% if doc.background_image %}
background: url("../files/{{ doc.background_image }}") repeat;
@ -7,22 +11,232 @@ body {
{% else %}
background-color: #edede7;
{% endif %}
{% if doc.font %}
font-family: '{{ doc.font }}', Verdana, Sans !important;
{% endif %}
{% if doc.font_size %}
font-size: {{ doc.font_size }} !important;
{% if doc.font or doc.google_web_font_for_text %}
font-family: '{{ doc.google_web_font_for_text or doc.font }}', 'Helvetica Neue', Arial, Sans !important;
{% endif %}
{% if doc.font_size %}font-size: {{ doc.font_size }} !important;{% endif %}
{% if doc.page_text %}color: #{{ doc.page_text }};{% endif %}
}
{% if doc.page_links %}a, a:hover {
color: #{{ doc.page_links }};
}{% endif %}
{% if doc.font_size %}
.small {
font-size: {{ doc.small_font_size }} !important;
}
{% endif %}
{% if doc.heading_font %}
h1, h2, h3, h4, h5 {
font-family: '{{ doc.heading_font}}', Arial, 'Helvetica Neue' !important;
}
div.outer {
background-color: #{{ doc.page_background or "fffffff" }};
}
{% if doc.google_web_font_for_heading or doc.heading_font %}h1, h2, h3, h4, h5 {
font-family: '{{ doc.google_web_font_for_heading or doc.heading_font }}', 'Helvetica Neue', Arial !important;
}{% endif %}
{% if doc.heading_text_style %}h1, h2, h3, h4, h5 {
text-transform: {{ doc.heading_text_style }};
}{% endif %}
{% if doc.page_headings %}h1, h2, h3, h4, h5 {
color: #{{ doc.page_headings }};
}{% endif %}
{% if doc.page_border %}
/* Page Border*/
div.outer {
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
-webkibox-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
}
{% else %}
{% if doc.background_color == doc.page_background %}
div.web-footer {
border-top: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
padding-top: 10px;
}
{% endif %}
{% endif %}
div.web-footer, div.web-footer a {
font-size: 90%;
color: #{{ get_hex_shade(doc.background_color or "ffffff", 70) }};
}
/* Bootstrap Navbar */
.navbar-inverse .navbar-inner {
background-color: #{{ doc.top_bar_background or "444444"}};
background-repeat: repeat-x;
border-color: transparent;
background-image: none;
}
.navbar-inner {
box-shadow: none;
}
{% if doc.top_bar_background == doc.page_background %}.navbar-inner {
border-bottom: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
}{% endif %}
.navbar-inverse .brand,
.navbar-inverse .brand:hover,
.navbar-inverse .brand:focus,
.navbar-inverse .nav > li > a {
color: #{{ doc.top_bar_foreground or "fffffff"}};
text-shadow: none;
}
.navbar-inverse .nav > li > a:hover,
.navbar-inverse .nav > li > a:focus {
color: #{{ doc.top_bar_background or "0000000"}};
}
.navbar-inverse .navbar-text {
color: #999999;
}
.navbar-inverse .nav > li > a:focus,
.navbar-inverse .nav > li > a:hover {
color: #{{ doc.top_bar_foreground or "fffffff"}};
background-color: transparent;
}
.navbar-inverse .nav .active > a,
.navbar-inverse .nav .active > a:hover,
.navbar-inverse .nav .active > a:focus {
color: #{{ doc.top_bar_foreground or "fffffff"}};
background-color: transparent;
}
.navbar-inverse .navbar-link {
color: #999999;
}
.navbar-inverse .navbar-link:hover,
.navbar-inverse .navbar-link:focus {
color: #{{ doc.top_bar_foreground or "fffffff"}};
}
.navbar-fixed-top .navbar-inner,
.navbar-static-top .navbar-inner {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.navbar .nav > .active > a,
.navbar .nav > .active > a:hover,
.navbar .nav > .active > a:focus {
color: #424242;
text-decoration: none;
background-color: transparent;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret,
.navbar-inverse .nav li.dropdown > .dropdown-toggle:hover .caret {
border-top-color: #{{ doc.top_bar_foreground or "fffffff"}};
border-bottom-color: #{{ doc.top_bar_foreground or "fffffff"}};
}
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle:hover .caret {
border-top-color: #{{ doc.top_bar_background or "0000000"}};
border-bottom-color: #{{ doc.top_bar_background or "0000000"}};
}
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle {
color: #{{ doc.top_bar_background or "0000000"}};
background-color: #{{ doc.top_bar_foreground or "fffffff"}};
}
@media (max-width: 800px) {
.navbar-inverse .nav-collapse .nav > li > a,
.navbar-inverse .nav-collapse .dropdown-menu a {
background-color: #{{ doc.top_bar_background or "0000000"}};
color: #{{ doc.top_bar_foreground or "fffffff"}};
}
.navbar-inverse .nav-collapse .nav > li > a:hover,
.navbar-inverse .nav-collapse .dropdown-menu a:hover {
background-color: #{{ doc.top_bar_foreground or "fffffff"}};
color: #{{ doc.top_bar_background or "0000000"}};
}
.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {
border-top-color: #{{ doc.top_bar_foreground or "fffffff" }};
border-bottom-color: #{{ doc.top_bar_foreground or "fffffff" }};
}
.navbar-inverse .nav li.dropdown > .dropdown-toggle:hover .caret {
border-top-color: #{{ doc.top_bar_background or "0000000" }};
border-bottom-color: #{{ doc.top_bar_background or "0000000" }};
}
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
.navbar-inverse .nav li.dropdown.open > .dropdown-toggle:hover .caret {
border-top-color: #{{ doc.top_bar_background or "0000000" }};
border-bottom-color: #{{ doc.top_bar_background or "0000000" }};
}
}
.breadcrumb {
background-color: #{{ get_hex_shade(doc.page_background or "ffffff", 10) }};
}
.breadcrumb > li {
text-shadow: none;
}
.breadcrumb > li > .divider {
color: #{{ doc.page_text }};
}
.breadcrumb > .active {
color: #{{ doc.page_text }};
}
.table-striped tbody > tr:nth-child(odd) > td,
.table-striped tbody > tr:nth-child(odd) > th {
background-color: #{{ get_hex_shade(doc.page_background or "ffffff", 5) }};
}
.table-hover tbody tr:hover td,
.table-hover tbody tr:hover th {
background-color: #{{ get_hex_shade(doc.page_background or "ffffff", 10) }};
}
.table-bordered {
border: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
}
.table th,
.table td {
border-top: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
}
.table-bordered th,
.table-bordered td {
border-left: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
}
.hero-unit {
background-color: #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
}
pre, code {
background-color: #{{ get_hex_shade(doc.page_background or "ffffff", 5) }};
}
hr {
border-top: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 15) }};
border-bottom: 1px solid #{{ get_hex_shade(doc.page_background or "ffffff", 5) }};
}

View File

@ -17,6 +17,9 @@
cur_frm.cscript.onload_post_render = function() {
wn.require('lib/public/js/lib/jscolor/jscolor.js');
cur_frm.fields_dict.background_color.input.className = 'color';
$.each(["background_color", "page_background", "page_text", "page_links",
"top_bar_background", "top_bar_foreground", "page_headings"], function(i, v) {
cur_frm.fields_dict[v].input.className = 'color';
})
jscolor.bind();
}

View File

@ -15,6 +15,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint, cstr
from webnotes import _
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
@ -22,26 +27,70 @@ class DocType:
def validate(self):
"""make custom css"""
from jinja2 import Template
from website.utils import get_hex_shade
import os
self.validate_colors()
with open(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'custom_template.css'), 'r') as f:
temp = Template(f.read())
if not self.doc.font_size:
self.doc.font_size = '13px'
self.doc.small_font_size = str(int(self.doc.font_size[:-2])-2) + 'px'
self.prepare()
self.doc.custom_css = temp.render(doc = self.doc)
self.doc.custom_css = temp.render(doc = self.doc, get_hex_shade=get_hex_shade)
if self.doc.add_css:
self.doc.custom_css += '\n\n/* User CSS */\n\n' + self.doc.add_css
from webnotes.sessions import clear_cache
clear_cache('Guest')
from website.utils import clear_cache
clear_cache()
del self.doc.fields['small_font_size']
for f in ["small_font_size", "at_import", "heading_text_style"]:
if f in self.doc.fields:
del self.doc.fields[f]
def validate_colors(self):
if (self.doc.page_background or self.doc.page_text) and \
self.doc.page_background==self.doc.page_text:
webnotes.msgprint(_("Page text and background is same color. Please change."),
raise_exception=1)
if (self.doc.top_bar_background or self.doc.top_bar_foreground) and \
self.doc.top_bar_background==self.doc.top_bar_foreground:
webnotes.msgprint(_("Top Bar text and background is same color. Please change."),
raise_exception=1)
def prepare(self):
if not self.doc.font_size:
self.doc.font_size = '13px'
self.doc.small_font_size = cstr(cint(self.doc.font_size[:-2])-2) + 'px'
self.doc.page_border = cint(self.doc.page_border)
fonts = []
if self.doc.google_web_font_for_heading:
fonts.append(self.doc.google_web_font_for_heading)
if self.doc.google_web_font_for_text:
fonts.append(self.doc.google_web_font_for_text)
fonts = list(set(fonts))
if self.doc.heading_text_as:
self.doc.heading_text_style = {
"UPPERCASE": "uppercase",
"Title Case":"capitalize",
"lowercase": "lowercase"
}[self.doc.heading_text_as]
self.doc.at_import = ""
for f in fonts:
self.doc.at_import += "\n@import url(http://fonts.googleapis.com/css?family=%s:400,700);" % f.replace(" ", "+")
def on_update(self):
"""rebuild pages"""

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-01-10 16:34:32",
"creation": "2013-03-08 11:36:53",
"docstatus": 0,
"modified": "2013-01-22 14:57:25",
"modified": "2013-03-14 11:57:20",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -24,23 +24,26 @@
"permlevel": 0
},
{
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Style Settings",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"report": 1,
"report": 0,
"role": "Website Manager",
"submit": 0,
"write": 1
"submit": 0
},
{
"doctype": "DocType",
"name": "Style Settings"
},
{
"doctype": "DocField",
"fieldname": "color",
"fieldtype": "Section Break",
"label": "Color"
},
{
"description": "If image is selected, color will be ignored (attach first)",
"doctype": "DocField",
@ -56,33 +59,109 @@
"fieldtype": "Data",
"label": "Background Color"
},
{
"doctype": "DocField",
"fieldname": "page_background",
"fieldtype": "Data",
"label": "Page Background"
},
{
"doctype": "DocField",
"fieldname": "page_border",
"fieldtype": "Check",
"label": "Page Border"
},
{
"doctype": "DocField",
"fieldname": "page_headings",
"fieldtype": "Data",
"label": "Page Headings"
},
{
"doctype": "DocField",
"fieldname": "page_text",
"fieldtype": "Data",
"label": "Page Text"
},
{
"doctype": "DocField",
"fieldname": "page_links",
"fieldtype": "Data",
"label": "Page Links"
},
{
"doctype": "DocField",
"fieldname": "cb0",
"fieldtype": "Column Break",
"label": "Top Bar",
"print_width": "50%",
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "top_bar_background",
"fieldtype": "Data",
"label": "Top Bar Background"
},
{
"description": "000 is black, fff is white",
"doctype": "DocField",
"fieldname": "top_bar_foreground",
"fieldtype": "Data",
"label": "Top Bar Text"
},
{
"doctype": "DocField",
"fieldname": "fonts",
"fieldtype": "Section Break",
"label": "Fonts"
},
{
"doctype": "DocField",
"fieldname": "heading_font",
"fieldtype": "Select",
"label": "Font (Heading)",
"options": "\nHelvetica Neue\nLucida Grande\nVerdana\nArial\nGeorgia\nTahoma\nLato\nOpen Sans"
},
{
"doctype": "DocField",
"fieldname": "font",
"fieldtype": "Select",
"label": "Font",
"label": "Font (Text)",
"options": "\nHelvetica Neue\nLucida Grande\nVerdana\nArial\nGeorgia\nTahoma"
},
{
"doctype": "DocField",
"fieldname": "font_size",
"fieldtype": "Select",
"label": "Font Size",
"label": "Font Size (Text)",
"options": "\n12px\n13px\n14px\n15px\n16px"
},
{
"doctype": "DocField",
"fieldname": "heading_font",
"fieldname": "heading_text_as",
"fieldtype": "Select",
"label": "Heading Font",
"options": "\nHelvetica Neue\nLucida Grande\nVerdana\nArial\nGeorgia\nTahoma\nLato\nOpen Sans"
"label": "Heading Text As",
"options": "\nUPPERCASE\nTitle Case\nlowercase"
},
{
"doctype": "DocField",
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"description": "Add the name of <a href=\"http://google.com/webfonts\" target=\"_blank\">Google Web Font</a> e.g. \"Open Sans\"",
"doctype": "DocField",
"fieldname": "google_web_font_for_heading",
"fieldtype": "Data",
"label": "Google Web Font (Heading)"
},
{
"description": "Add the name of <a href=\"http://google.com/webfonts\" target=\"_blank\">Google Web Font</a> e.g. \"Open Sans\"",
"doctype": "DocField",
"fieldname": "google_web_font_for_text",
"fieldtype": "Data",
"label": "Google Web Font (Text)"
},
{
"doctype": "DocField",
@ -115,6 +194,16 @@
"print_hide": 1
},
{
"doctype": "DocPerm"
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1
}
]

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-01-27 16:31:21",
"creation": "2013-02-12 13:19:11",
"docstatus": 0,
"modified": "2013-02-12 09:33:47",
"modified": "2013-03-11 17:41:11",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -24,18 +24,16 @@
"permlevel": 0
},
{
"create": 1,
"amend": 0,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Web Page",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"report": 1,
"role": "Website Manager",
"submit": 0,
"write": 1
"submit": 0
},
{
"doctype": "DocType",
@ -85,6 +83,13 @@
"label": "Slideshow",
"options": "Website Slideshow"
},
{
"description": "Description for page header.",
"doctype": "DocField",
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description"
},
{
"description": "Content in markdown format that appears on the main side of your page",
"doctype": "DocField",
@ -143,6 +148,17 @@
"print_hide": 1
},
{
"doctype": "DocPerm"
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"write": 1
},
{
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1,
"write": 0
}
]

View File

@ -41,4 +41,14 @@ $.extend(cur_frm.cscript, {
this.fieldobj.refresh_options(get_parent_options('top_bar_items'));
});
}
});
});
cur_frm.cscript.set_banner_from_image = function(doc) {
if(!doc.banner_image) {
msgprint(wn._("Select a Banner Image first."));
}
var src = doc.banner_image;
if(src.indexOf("/")==-1) src = "files/" + src;
cur_frm.set_value("banner_html", "<a href='/'><img src='"+ src
+"' style='max-width: 200px;'></a>");
}

View File

@ -31,9 +31,6 @@ class DocType:
from website.utils import clear_cache
clear_cache()
from webnotes.sessions import clear_cache
clear_cache('Guest')
def set_home_page(self):
import webnotes

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-01-25 11:35:10",
"creation": "2013-03-07 11:55:11",
"docstatus": 0,
"modified": "2013-02-21 10:05:09",
"modified": "2013-03-13 16:25:22",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -72,24 +72,45 @@
"label": "Home Page is Products"
},
{
"description": "Add a banner to the site. (small banners are usually good)",
"doctype": "DocField",
"fieldname": "banner",
"fieldtype": "Section Break",
"label": "Banner"
},
{
"description": "Select an image of approx width 150px with a transparent background for best results.",
"doctype": "DocField",
"fieldname": "banner_image",
"fieldtype": "Select",
"label": "Banner Image",
"options": "attach_files:"
},
{
"doctype": "DocField",
"fieldname": "set_banner_from_image",
"fieldtype": "Button",
"label": "Set Banner from Image"
},
{
"description": "Banner is above the Top Menu Bar.",
"doctype": "DocField",
"fieldname": "banner_html",
"fieldtype": "Small Text",
"label": "Banner HTML"
},
{
"description": "Menu items in the Top Bar. For setting the color of the Top Bar, go to <a href=\"#Form/Style Settings\">Style Settings</a>",
"doctype": "DocField",
"fieldname": "top_bar",
"fieldtype": "Section Break",
"label": "Top Bar"
},
{
"description": "Background shade of the top menu bar",
"doctype": "DocField",
"fieldname": "top_bar_background",
"fieldtype": "Select",
"label": "Top Bar Background",
"options": "Black\nWhite"
},
{
"description": "Brand is what appears on the top-right of the toolbar. If it is an image, make sure it\nhas a transparent background and use the &lt;img /&gt; tag. Keep size as 200px x 30px",
"doctype": "DocField",
"fieldname": "brand_html",
"fieldtype": "Text",
"fieldtype": "Small Text",
"label": "Brand HTML"
},
{

View File

@ -4,41 +4,51 @@
from __future__ import unicode_literals
import webnotes
import website.utils
from webnotes import _
def clear_blog_cache():
for blog in webnotes.conn.sql_list("""select page_name from
`tabBlog Post` where ifnull(published,0)=1"""):
website.utils.delete_page_cache(blog)
website.utils.delete_page_cache("writers")
@webnotes.whitelist(allow_guest=True)
def get_blog_list(args=None):
"""
args = {
'start': 0,
}
"""
def get_blog_list(start=0, by=None, category=None):
import webnotes
if not args: args = webnotes.form_dict
condition = ""
if by:
condition = " and t1.blogger='%s'" % by.replace("'", "\'")
if category:
condition += " and t1.blog_category='%s'" % category.replace("'", "\'")
query = """\
select
name, page_name, content, owner, creation as creation,
title, (select count(name) from `tabComment` where
comment_doctype='Blog' and comment_docname=`tabBlog`.name) as comments
from `tabBlog`
where ifnull(published,0)=1
order by creation desc, name asc
limit %s, 5""" % args.start
t1.title, t1.name, t1.page_name, t1.published_on as creation,
ifnull(t1.blog_intro, t1.content) as content,
t2.full_name, t2.avatar, t1.blogger,
(select count(name) from `tabComment` where
comment_doctype='Blog Post' and comment_docname=t1.name) as comments
from `tabBlog Post` t1, `tabBlogger` t2
where ifnull(t1.published,0)=1
and t1.blogger = t2.name
%(condition)s
order by published_on desc, name asc
limit %(start)s, 20""" % {"start": start, "condition": condition}
result = webnotes.conn.sql(query, args, as_dict=1)
result = webnotes.conn.sql(query, as_dict=1)
# strip html tags from content
import webnotes.utils
for res in result:
from webnotes.utils import global_date_format, get_fullname
res['full_name'] = get_fullname(res['owner'])
res['published'] = global_date_format(res['creation'])
if not res['content']:
res['content'] = website.utils.get_html(res['page_name'])
res['content'] = split_blog_content(res['content'])
res['content'] = res['content'][:140]
if res.avatar and not "/" in res.avatar:
res.avatar = "files/" + res.avatar
return result
@webnotes.whitelist(allow_guest=True)
@ -73,10 +83,10 @@ def add_comment(args=None):
# notify commentors
commentors = [d[0] for d in webnotes.conn.sql("""select comment_by from tabComment where
comment_doctype='Blog' and comment_docname=%s and
comment_doctype='Blog Post' and comment_docname=%s and
ifnull(unsubscribed, 0)=0""", args.get('comment_docname'))]
blog = webnotes.conn.sql("""select * from tabBlog where name=%s""",
blog = webnotes.conn.sql("""select * from `tabBlog Post` where name=%s""",
args.get('comment_docname'), as_dict=1)[0]
from webnotes.utils.email_lib.bulk import send
@ -89,10 +99,8 @@ def add_comment(args=None):
return comment_html
@webnotes.whitelist(allow_guest=True)
def add_subscriber():
def add_subscriber(name, email_id):
"""add blog subscriber to lead"""
full_name = webnotes.form_dict.get('your_name')
email = webnotes.form_dict.get('your_email_address')
name = webnotes.conn.sql("""select name from tabLead where email_id=%s""", email)
from webnotes.model.doc import Document
@ -104,21 +112,38 @@ def add_subscriber():
if not lead.source: lead.source = 'Blog'
lead.unsubscribed = 0
lead.blog_subscriber = 1
lead.lead_name = full_name
lead.lead_name = name
lead.email_id = email
lead.save()
def get_blog_content(blog_page_name):
import website.utils
content = website.utils.get_html(blog_page_name)
content = split_blog_content(content)
import webnotes.utils
content = webnotes.utils.escape_html(content)
return content
def get_blog_template_args():
args = {
"categories": webnotes.conn.sql_list("select name from `tabBlog Category` order by name")
}
args.update(webnotes.doc("Blog Settings", "Blog Settings").fields)
return args
def split_blog_content(content):
content = content.split("<!-- begin blog content -->")
content = len(content) > 1 and content[1] or content[0]
content = content.split("<!-- end blog content -->")
content = content[0]
return content
def get_writers_args():
bloggers = webnotes.conn.sql("""select * from `tabBlogger`
order by posts desc""", as_dict=1)
for blogger in bloggers:
if blogger.avatar and not "/" in blogger.avatar:
blogger.avatar = "files/" + blogger.avatar
args = {
"bloggers": bloggers,
"texts": {
"all_posts_by": _("All posts by")
},
"categories": webnotes.conn.sql_list("select name from `tabBlog Category` order by name")
}
args.update(webnotes.doc("Blog Settings", "Blog Settings").fields)
return args

View File

@ -44,7 +44,7 @@ rss_item = u"""
<description>%(content)s</description>
<link>%(link)s</link>
<guid>%(name)s</guid>
<pubDate>%(creation)s</pubDate>
<pubDate>%(published_on)s</pubDate>
</item>"""
def generate():
@ -57,13 +57,12 @@ def generate():
items = ''
blog_list = webnotes.conn.sql("""\
select page_name as name, modified, creation, title from tabBlog
select page_name as name, published_on, modified, title, content from `tabBlog Post`
where ifnull(published,0)=1
order by creation desc, modified desc, name asc limit 100""", as_dict=1)
order by published_on desc limit 20""", as_dict=1)
for blog in blog_list:
blog.link = host + '/' + blog.name + '.html'
blog.content = get_blog_content(blog.name)
items += rss_item % blog

View File

@ -11,11 +11,6 @@ wn.module_page["Website"] = [
description: wn._("Content web page."),
doctype:"Web Page"
},
{
label: wn._("Blog"),
description: wn._("Blog entry."),
doctype:"Blog"
},
{
label: wn._("Website Slideshow"),
description: wn._("Embed image slideshows in website pages."),
@ -23,6 +18,34 @@ wn.module_page["Website"] = [
},
]
},
{
title: wn._("Blog"),
icon: "icon-edit",
items: [
{
label: wn._("Blog Post"),
description: wn._("Single Post (article)."),
doctype:"Blog Post"
},
{
label: wn._("Blogger"),
description: wn._("Profile of a blog writer."),
doctype:"Blogger"
},
{
label: wn._("Blog Category"),
description: wn._("Categorize blog posts."),
doctype:"Blog Category"
},
{
label: wn._("Blog Settings"),
description: wn._("Write titles and introductions to your blog."),
doctype:"Blog Settings",
route: "Form/Blog Settings"
},
]
},
{
title: wn._("Website Overall Settings"),
icon: "icon-wrench",
@ -45,6 +68,7 @@ wn.module_page["Website"] = [
{
title: wn._("Special Page Settings"),
icon: "icon-wrench",
right: true,
items: [
{
"route":"Form/Product Settings",

View File

@ -6,6 +6,7 @@
.layout-wrapper {
background-color: #fff;
color: #333;
padding: 10px;
box-shadow: 1px 1px 3px 3px #ccc;
font-size: 12px;

View File

@ -19,6 +19,9 @@
<link rel="icon" href="app/images/favicon.ico" type="image/x-icon">
{% endif %}
{% if description %}
<meta name="description" content="{{ description }}">
{% endif %}
{% block header %}
{% endblock %}

Some files were not shown because too many files have changed in this diff Show More