diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 47e3195d71..b31d54919c 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -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 diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index fb290d27e3..1f165f0c33 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -38,72 +38,199 @@ 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): + si = webnotes.bean(webnotes.copy_doclist(test_records[1])) + si.insert() + si.submit() + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + 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) + + def test_sales_invoice_gl_entry_with_aii(self): + 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 = 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] + ]) + print expected_values + print gl_entries + 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", 1) + + + 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 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, - } -]] \ No newline at end of file +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, + } + ], + [ + { + "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": 1.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", + "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, + } + ], +] \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index d136820c2e..2751854ee0 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -16,7 +16,6 @@ from __future__ import unicode_literals patch_list = [ - "execute:webnotes.reload_doc('core', 'doctype', 'report') # 2013-03-07", "patches.mar_2012.so_rv_mapper_fix", "patches.mar_2012.clean_property_setter", "patches.april_2012.naming_series_patch", @@ -209,4 +208,5 @@ 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", + "execute:webnotes.bean('Style Settings', 'Style Settings').save()" ] \ No newline at end of file diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py index 47d139f955..12ae4a8c90 100644 --- a/selling/doctype/sales_common/sales_common.py +++ b/selling/doctype/sales_common/sales_common.py @@ -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) # =========================================================================== diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py index c2bb5d07ca..acdf8b9e07 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -109,7 +109,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, diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py index 05fc0e0642..5dff992ae4 100644 --- a/stock/doctype/stock_ledger/stock_ledger.py +++ b/stock/doctype/stock_ledger/stock_ledger.py @@ -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() diff --git a/website/css/website.css b/website/css/website.css index 956f22e8bc..dc5b9670b3 100644 --- a/website/css/website.css +++ b/website/css/website.css @@ -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; } - -/* */ \ No newline at end of file diff --git a/website/doctype/blog/blog.py b/website/doctype/blog/blog.py index cfc0ca643e..d7ffdac567 100644 --- a/website/doctype/blog/blog.py +++ b/website/doctype/blog/blog.py @@ -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,6 +28,9 @@ class DocType: from website.utils import page_name self.doc.name = page_name(self.doc.title) + def validate(self): + self.doc.blog_intro = self.doc.blog_intro[:140] + def on_update(self): from website.utils import update_page_name update_page_name(self.doc, self.doc.title) @@ -66,6 +70,20 @@ class DocType: self.doc.full_name = get_fullname(self.doc.owner) self.doc.updated = global_date_format(self.doc.creation) 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.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 diff --git a/website/doctype/blog/blog.txt b/website/doctype/blog/blog.txt index af9606a71b..e4c92c2e2d 100644 --- a/website/doctype/blog/blog.txt +++ b/website/doctype/blog/blog.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-02-21 16:54:04", + "modified": "2013-03-08 09:41:37", "modified_by": "Administrator", "owner": "Administrator" }, @@ -50,18 +50,44 @@ "label": "Published" }, { - "description": "Description for listing page, in plain text, only a couple of lines.", + "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", diff --git a/website/doctype/blog_category/__init__.py b/website/doctype/blog_category/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website/doctype/blog_category/blog_category.py b/website/doctype/blog_category/blog_category.py new file mode 100644 index 0000000000..c8c369c4c0 --- /dev/null +++ b/website/doctype/blog_category/blog_category.py @@ -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() + \ No newline at end of file diff --git a/website/doctype/blog_category/blog_category.txt b/website/doctype/blog_category/blog_category.txt new file mode 100644 index 0000000000..cf8cad66bf --- /dev/null +++ b/website/doctype/blog_category/blog_category.txt @@ -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" + } +] \ No newline at end of file diff --git a/website/doctype/blogger/__init__.py b/website/doctype/blogger/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website/doctype/blogger/blogger.py b/website/doctype/blogger/blogger.py new file mode 100644 index 0000000000..28d0f29b3e --- /dev/null +++ b/website/doctype/blogger/blogger.py @@ -0,0 +1,18 @@ +# 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" + if self.doc.profile: + for blog in webnotes.conn.sql_list("""select name from tabBlog where owner=%s + and ifnull(blogger,'')=''""", self.doc.profile): + b = webnotes.bean("Blog", blog) + b.blogger = self.doc.name + b.save() + diff --git a/website/doctype/blogger/blogger.txt b/website/doctype/blogger/blogger.txt new file mode 100644 index 0000000000..01e0ceae20 --- /dev/null +++ b/website/doctype/blogger/blogger.txt @@ -0,0 +1,95 @@ +[ + { + "creation": "2013-03-07 16:28:19", + "docstatus": 0, + "modified": "2013-03-07 16:33: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": "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" + } +] \ No newline at end of file diff --git a/website/doctype/style_settings/custom_template.css b/website/doctype/style_settings/custom_template.css index 9009bbe18a..e625f95856 100644 --- a/website/doctype/style_settings/custom_template.css +++ b/website/doctype/style_settings/custom_template.css @@ -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,8 +11,8 @@ body { {% else %} background-color: #edede7; {% endif %} -{% if doc.font %} - font-family: '{{ doc.font }}', Verdana, Sans !important; +{% if doc.font or doc.google_web_font_for_text %} + font-family: '{{ doc.google_web_font_for_text or doc.font }}', Verdana, Sans !important; {% endif %} {% if doc.font_size %} font-size: {{ doc.font_size }} !important; @@ -21,8 +25,106 @@ body { } {% endif %} -{% if doc.heading_font %} +div.outer { + background-color: #{{ doc.page_background or "fff" }}; +} + +{% if doc.google_web_font_for_heading or doc.heading_font %} h1, h2, h3, h4, h5 { - font-family: '{{ doc.heading_font}}', Arial, 'Helvetica Neue' !important; + font-family: '{{ doc.google_web_font_for_heading or doc.heading_font }}', Arial, 'Helvetica Neue' !important; +} +{% endif %} +{% if doc.heading_text_as %} +h1, h2, h3, h4, h5 { + text-transform: {{ doc.heading_text_as }}; } {% endif %} + +{% if doc.page_border %} +/* Page Border*/ +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); + border-radius: 5px; +} +{% else %} +div.web-footer { + border-top: 1px solid #eee; + padding-top: 10px; +} +{% endif %} + +/* Bootstrap Navbar */ +.navbar-inverse .navbar-inner { + background-color: #{{ doc.top_bar_background or "444"}}; + background-repeat: repeat-x; + border-color: transparent; + background-image: none; +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #{{ doc.top_bar_foreground or "fff"}}; + text-shadow: none; +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #{{ doc.top_bar_foreground or "fff"}}; +} + +.navbar-inverse .brand { + color: #{{ doc.top_bar_foreground or "fff"}}; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #{{ doc.top_bar_foreground or "fff"}}; + 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 "fff"}}; + 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 "fff"}}; +} + +.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 { + border-top-color: #{{ doc.top_bar_foreground or "fff"}}; + border-bottom-color: #{{ doc.top_bar_foreground or "fff"}}; +} diff --git a/website/doctype/style_settings/style_settings.js b/website/doctype/style_settings/style_settings.js index 54091a38f2..e8ee908799 100644 --- a/website/doctype/style_settings/style_settings.js +++ b/website/doctype/style_settings/style_settings.js @@ -18,5 +18,7 @@ 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'; + cur_frm.fields_dict.page_background.input.className = 'color'; + cur_frm.fields_dict.top_bar_background.input.className = 'color'; jscolor.bind(); } \ No newline at end of file diff --git a/website/doctype/style_settings/style_settings.py b/website/doctype/style_settings/style_settings.py index 51799483d4..0a1a2e0203 100644 --- a/website/doctype/style_settings/style_settings.py +++ b/website/doctype/style_settings/style_settings.py @@ -15,6 +15,8 @@ # along with this program. If not, see . from __future__ import unicode_literals +from webnotes.utils import cint, cstr + class DocType: def __init__(self, d, dl): self.doc, self.doclist = d, dl @@ -29,10 +31,7 @@ class DocType: '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) if self.doc.add_css: @@ -41,7 +40,36 @@ class DocType: from webnotes.sessions import clear_cache clear_cache('Guest') - del self.doc.fields['small_font_size'] + for f in ["small_font_size", "at_import"]: + if f in self.doc.fields: + del self.doc.fields[f] + + 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_as = { + "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);" % f.replace(" ", "+") + def on_update(self): """rebuild pages""" diff --git a/website/doctype/style_settings/style_settings.txt b/website/doctype/style_settings/style_settings.txt index 5f53441ea8..e58ae09e95 100644 --- a/website/doctype/style_settings/style_settings.txt +++ b/website/doctype/style_settings/style_settings.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-10 16:34:32", + "creation": "2013-01-25 11:35:10", "docstatus": 0, - "modified": "2013-01-22 14:57:25", + "modified": "2013-03-08 09:58:49", "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,6 +59,18 @@ "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": "cb0", @@ -63,26 +78,72 @@ "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": "Select", + "label": "Top Bar Foreground", + "options": "000\nFFF" + }, + { + "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 Google Web Font e.g. \"Open Sans\"", + "doctype": "DocField", + "fieldname": "google_web_font_for_heading", + "fieldtype": "Data", + "label": "Google Web Font (Heading)" + }, + { + "description": "Add the name of Google Web Font e.g. \"Open Sans\"", + "doctype": "DocField", + "fieldname": "google_web_font_for_text", + "fieldtype": "Data", + "label": "Google Web Font (Text)" }, { "doctype": "DocField", @@ -115,6 +176,16 @@ "print_hide": 1 }, { - "doctype": "DocPerm" + "create": 1, + "doctype": "DocPerm", + "permlevel": 0, + "write": 1 + }, + { + "amend": 0, + "cancel": 0, + "create": 0, + "doctype": "DocPerm", + "permlevel": 1 } ] \ No newline at end of file diff --git a/website/doctype/website_settings/website_settings.py b/website/doctype/website_settings/website_settings.py index 88af6348ac..714b75a75d 100644 --- a/website/doctype/website_settings/website_settings.py +++ b/website/doctype/website_settings/website_settings.py @@ -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 diff --git a/website/helpers/blog.py b/website/helpers/blog.py index 2bff6e5708..d90c85aad0 100644 --- a/website/helpers/blog.py +++ b/website/helpers/blog.py @@ -4,41 +4,44 @@ from __future__ import unicode_literals import webnotes import website.utils +from webnotes import _ @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 + t1.title, t1.name, t1.page_name, t1.creation 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' and comment_docname=t1.name) as comments + from `tabBlog` t1, `tabBlogger` t2 + where ifnull(t1.published,0)=1 + and t1.blogger = t2.name + %(condition)s order by creation desc, name asc - limit %s, 5""" % args.start + limit %(start)s, 5""" % {"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) @@ -115,10 +118,22 @@ def get_blog_content(blog_page_name): import webnotes.utils content = webnotes.utils.escape_html(content) return content + +def get_blog_template_args(): + return { + "categories": webnotes.conn.sql_list("select name from `tabBlog Category` order by name") + } -def split_blog_content(content): - content = content.split("") - content = len(content) > 1 and content[1] or content[0] - content = content.split("") - content = content[0] - return content \ No newline at end of file +def get_writers_args(): + bloggers = webnotes.conn.sql("select * from `tabBlogger` order by full_name", as_dict=1) + for blogger in bloggers: + if blogger.avatar and not "/" in blogger.avatar: + blogger.avatar = "files/" + blogger.avatar + + return { + "bloggers": bloggers, + "texts": { + "all_posts_by": _("All posts by") + }, + "categories": webnotes.conn.sql_list("select name from `tabBlog Category` order by name") + } \ No newline at end of file diff --git a/website/page/website_home/website_home.js b/website/page/website_home/website_home.js index c6b2253df1..40e29e87a4 100644 --- a/website/page/website_home/website_home.js +++ b/website/page/website_home/website_home.js @@ -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,28 @@ wn.module_page["Website"] = [ }, ] }, + { + title: wn._("Blog"), + icon: "icon-edit", + items: [ + { + label: wn._("Blog"), + description: wn._("Blog post."), + doctype:"Blog" + }, + { + label: wn._("Blogger"), + description: wn._("Profile of a blog writer."), + doctype:"Blogger" + }, + { + label: wn._("Blog Category"), + description: wn._("Categorize blog posts."), + doctype:"Blogger" + }, + ] + }, + { title: wn._("Website Overall Settings"), icon: "icon-wrench", diff --git a/website/templates/html/blog_footer.html b/website/templates/html/blog_footer.html new file mode 100644 index 0000000000..e439d14729 --- /dev/null +++ b/website/templates/html/blog_footer.html @@ -0,0 +1,13 @@ +
+
+ {% if categories %} +
Explore posts by categories
+
diff --git a/website/templates/html/blog_page.html b/website/templates/html/blog_page.html index 24dd8d7acc..e605a12248 100644 --- a/website/templates/html/blog_page.html +++ b/website/templates/html/blog_page.html @@ -13,41 +13,41 @@

{{ title }}

-
By {{ full_name }} on {{ updated }}
+
+ {{ blogger_info and blogger_info.full_name or full_name }} / {{ updated }}

{{ content_html }} - + {% if blogger_info %} +
+ {% include "html/blogger.html" %} + {% endif %}
-

Comments


+

{{ texts.comments }}


{% if not comment_list %} -
-

Be the first one to comment

+
+

{{ texts.first_comment }}

{% endif %} {% include 'html/comment.html' %}
-
+
+{% include 'html/blog_footer.html' %} {% endblock %} \ No newline at end of file diff --git a/website/templates/html/blogger.html b/website/templates/html/blogger.html new file mode 100644 index 0000000000..eab371e45b --- /dev/null +++ b/website/templates/html/blogger.html @@ -0,0 +1,13 @@ +
+
+
+ +
+
+
+

{{ blogger_info.full_name }}

+

{{ blogger_info.bio }}

+

+ {{ texts.all_posts_by }} {{ blogger_info.full_name }}

+
+
\ No newline at end of file diff --git a/website/templates/html/outer.html b/website/templates/html/outer.html index de961227b3..e582d0a9ce 100644 --- a/website/templates/html/outer.html +++ b/website/templates/html/outer.html @@ -6,7 +6,7 @@