mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-19 21:19:19 +00:00
[cleanup] code commonified of making sl entry
This commit is contained in:
@@ -213,7 +213,7 @@ class DocType(SellingController):
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# create stock ledger entry
|
||||
self.update_stock_ledger(update_stock = 1)
|
||||
self.update_stock_ledger()
|
||||
|
||||
self.credit_limit()
|
||||
|
||||
@@ -258,7 +258,7 @@ class DocType(SellingController):
|
||||
|
||||
self.update_prevdoc_status()
|
||||
|
||||
self.update_stock_ledger(update_stock = -1)
|
||||
self.update_stock_ledger()
|
||||
webnotes.conn.set(self.doc, 'status', 'Cancelled')
|
||||
self.cancel_packing_slips()
|
||||
|
||||
@@ -292,57 +292,32 @@ class DocType(SellingController):
|
||||
webnotes.msgprint(_("Packing Slip(s) Cancelled"))
|
||||
|
||||
|
||||
def update_stock_ledger(self, update_stock):
|
||||
self.values = []
|
||||
def update_stock_ledger(self):
|
||||
sl_entries = []
|
||||
for d in self.get_item_list():
|
||||
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
|
||||
|
||||
if d.item_code in self.stock_items and d.warehouse:
|
||||
if d['reserved_qty'] < 0 :
|
||||
# Reduce reserved qty from reserved warehouse mentioned in so
|
||||
args = {
|
||||
"item_code": d['item_code'],
|
||||
"voucher_type": self.doc.doctype,
|
||||
"voucher_no": self.doc.name,
|
||||
"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
|
||||
"reserved_qty": (self.doc.docstatus==1 and 1 or -1)*flt(d['reserved_qty']),
|
||||
"posting_date": self.doc.posting_date,
|
||||
"is_amended": self.doc.amended_from and 'Yes' or 'No'
|
||||
}
|
||||
get_obj("Warehouse", d["reserved_warehouse"]).update_bin(args)
|
||||
|
||||
# Reduce actual qty from warehouse
|
||||
self.make_sl_entry(d, d['warehouse'], - flt(d['qty']) , 0, update_stock)
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"actual_qty": -1*flt(d['qty']),
|
||||
}))
|
||||
|
||||
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
|
||||
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def get_item_list(self):
|
||||
return get_obj('Sales Common').get_item_list(self)
|
||||
|
||||
|
||||
def make_sl_entry(self, d, wh, qty, in_value, update_stock):
|
||||
self.values.append({
|
||||
'item_code' : d['item_code'],
|
||||
'warehouse' : wh,
|
||||
'posting_date' : self.doc.posting_date,
|
||||
'posting_time' : self.doc.posting_time,
|
||||
'voucher_type' : 'Delivery Note',
|
||||
'voucher_no' : self.doc.name,
|
||||
'voucher_detail_no' : d['name'],
|
||||
'actual_qty' : qty,
|
||||
'stock_uom' : d['uom'],
|
||||
'incoming_rate' : in_value,
|
||||
'company' : self.doc.company,
|
||||
'fiscal_year' : self.doc.fiscal_year,
|
||||
'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
|
||||
'batch_no' : d['batch_no'],
|
||||
'serial_no' : d['serial_no'],
|
||||
"project" : self.doc.project_name
|
||||
})
|
||||
|
||||
|
||||
def credit_limit(self):
|
||||
"""check credit limit of items in DN Detail which are not fetched from sales order"""
|
||||
amount, total = 0, 0
|
||||
|
||||
@@ -170,14 +170,11 @@ class DocType(BuyingController):
|
||||
d.rejected_serial_no = cstr(d.rejected_serial_no).strip().replace(',', '\n')
|
||||
d.save()
|
||||
|
||||
def update_stock(self, is_submit):
|
||||
def update_stock(self):
|
||||
pc_obj = get_obj('Purchase Common')
|
||||
self.values = []
|
||||
sl_entries = []
|
||||
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
|
||||
|
||||
if d.item_code in self.stock_items and d.warehouse:
|
||||
ord_qty = 0
|
||||
pr_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||
|
||||
@@ -200,51 +197,27 @@ class DocType(BuyingController):
|
||||
args = {
|
||||
"item_code": d.item_code,
|
||||
"posting_date": self.doc.posting_date,
|
||||
"ordered_qty": (is_submit and 1 or -1) * flt(ord_qty)
|
||||
"ordered_qty": (self.doc.docstatus==1 and 1 or -1) * flt(ord_qty)
|
||||
}
|
||||
get_obj("Warehouse", d.warehouse).update_bin(args)
|
||||
|
||||
# UPDATE actual qty to warehouse by pr_qty
|
||||
if pr_qty:
|
||||
self.make_sl_entry(d, d.warehouse, flt(pr_qty), d.valuation_rate, is_submit)
|
||||
|
||||
# UPDATE actual to rejected warehouse by rejected qty
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"actual_qty": flt(pr_qty),
|
||||
"serial_no": cstr(d.serial_no).strip()
|
||||
}))
|
||||
|
||||
if flt(d.rejected_qty) > 0:
|
||||
self.make_sl_entry(d, self.doc.rejected_warehouse, flt(d.rejected_qty) * flt(d.conversion_factor), d.valuation_rate, is_submit, rejected = 1)
|
||||
|
||||
self.bk_flush_supp_wh(is_submit)
|
||||
|
||||
if self.values:
|
||||
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
|
||||
|
||||
|
||||
# make Stock Entry
|
||||
def make_sl_entry(self, d, wh, qty, in_value, is_submit, rejected = 0):
|
||||
if rejected:
|
||||
serial_no = cstr(d.rejected_serial_no).strip()
|
||||
else:
|
||||
serial_no = cstr(d.serial_no).strip()
|
||||
|
||||
self.values.append({
|
||||
'item_code' : d.fields.has_key('item_code') and d.item_code or d.rm_item_code,
|
||||
'warehouse' : wh,
|
||||
'posting_date' : self.doc.posting_date,
|
||||
'posting_time' : self.doc.posting_time,
|
||||
'voucher_type' : 'Purchase Receipt',
|
||||
'voucher_no' : self.doc.name,
|
||||
'voucher_detail_no' : d.name,
|
||||
'actual_qty' : qty,
|
||||
'stock_uom' : d.stock_uom,
|
||||
'incoming_rate' : in_value,
|
||||
'company' : self.doc.company,
|
||||
'fiscal_year' : self.doc.fiscal_year,
|
||||
'is_cancelled' : (is_submit==1) and 'No' or 'Yes',
|
||||
'batch_no' : cstr(d.batch_no).strip(),
|
||||
'serial_no' : serial_no,
|
||||
"project" : d.project_name
|
||||
})
|
||||
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"warehouse": self.doc.rejected_warehouse,
|
||||
"actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor),
|
||||
"serial_no": cstr(d.rejected_serial_no).strip()
|
||||
}))
|
||||
|
||||
self.bk_flush_supp_wh(sl_entries)
|
||||
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def validate_inspection(self):
|
||||
for d in getlist(self.doclist, 'purchase_receipt_details'): #Enter inspection date for all items that require inspection
|
||||
ins_reqd = sql("select inspection_required from `tabItem` where name = %s",
|
||||
@@ -278,7 +251,7 @@ class DocType(BuyingController):
|
||||
get_obj('Stock Ledger').update_serial_record(self, 'purchase_receipt_details', is_submit = 1, is_incoming = 1)
|
||||
|
||||
# Update Stock
|
||||
self.update_stock(is_submit = 1)
|
||||
self.update_stock()
|
||||
|
||||
# Update last purchase rate
|
||||
purchase_controller.update_last_purchase_rate(self, 1)
|
||||
@@ -310,23 +283,23 @@ class DocType(BuyingController):
|
||||
# 3. Cancel Serial No
|
||||
get_obj('Stock Ledger').update_serial_record(self, 'purchase_receipt_details', is_submit = 0, is_incoming = 1)
|
||||
|
||||
# 4.Update Bin
|
||||
self.update_stock(is_submit = 0)
|
||||
|
||||
self.update_stock()
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# 6. Update last purchase rate
|
||||
pc_obj.update_last_purchase_rate(self, 0)
|
||||
|
||||
self.make_cancel_gl_entries()
|
||||
|
||||
def bk_flush_supp_wh(self, is_submit):
|
||||
def bk_flush_supp_wh(self, sl_entries):
|
||||
for d in getlist(self.doclist, 'pr_raw_material_details'):
|
||||
# negative quantity is passed as raw material qty has to be decreased
|
||||
# when PR is submitted and it has to be increased when PR is cancelled
|
||||
consumed_qty = - flt(d.consumed_qty)
|
||||
self.make_sl_entry(d, self.doc.supplier_warehouse, flt(consumed_qty), 0, is_submit)
|
||||
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"item_code": d.rm_item_code,
|
||||
"warehouse": self.doc.supplier_warehouse,
|
||||
"actual_qty": -1*flt(consumed_qty),
|
||||
"incoming_rate": 0
|
||||
}))
|
||||
|
||||
def get_current_stock(self):
|
||||
for d in getlist(self.doclist, 'pr_raw_material_details'):
|
||||
if self.doc.supplier_warehouse:
|
||||
|
||||
@@ -75,8 +75,7 @@ class DocType(StockController):
|
||||
self.make_gl_entries()
|
||||
|
||||
def make_stock_ledger_entry(self, qty):
|
||||
from webnotes.model.code import get_obj
|
||||
values = [{
|
||||
sl_entries = [{
|
||||
'item_code' : self.doc.item_code,
|
||||
'warehouse' : self.doc.warehouse,
|
||||
'posting_date' : self.doc.purchase_date or (self.doc.creation and self.doc.creation.split(' ')[0]) or nowdate(),
|
||||
@@ -93,8 +92,8 @@ class DocType(StockController):
|
||||
'batch_no' : '',
|
||||
'serial_no' : self.doc.name
|
||||
}]
|
||||
get_obj('Stock Ledger').update_stock(values)
|
||||
|
||||
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def on_trash(self):
|
||||
if self.doc.status == 'Delivered':
|
||||
|
||||
@@ -65,13 +65,13 @@ class DocType(StockController):
|
||||
|
||||
def on_submit(self):
|
||||
self.update_serial_no(1)
|
||||
self.update_stock_ledger(0)
|
||||
self.update_stock_ledger()
|
||||
self.update_production_order(1)
|
||||
self.make_gl_entries()
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_serial_no(0)
|
||||
self.update_stock_ledger(1)
|
||||
self.update_stock_ledger()
|
||||
self.update_production_order(0)
|
||||
self.make_cancel_gl_entries()
|
||||
|
||||
@@ -351,16 +351,24 @@ class DocType(StockController):
|
||||
serial_doc.docstatus = is_submit and 2 or 0
|
||||
serial_doc.save()
|
||||
|
||||
def update_stock_ledger(self, is_cancelled=0):
|
||||
self.values = []
|
||||
def update_stock_ledger(self):
|
||||
sl_entries = []
|
||||
for d in getlist(self.doclist, 'mtn_details'):
|
||||
if cstr(d.s_warehouse):
|
||||
self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled)
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"warehouse": cstr(d.s_warehouse),
|
||||
"actual_qty": -flt(d.transfer_qty),
|
||||
"incoming_rate": flt(d.incoming_rate)
|
||||
}))
|
||||
|
||||
if cstr(d.t_warehouse):
|
||||
self.add_to_values(d, cstr(d.t_warehouse), flt(d.transfer_qty), is_cancelled)
|
||||
|
||||
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values,
|
||||
self.doc.amended_from and 'Yes' or 'No')
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"warehouse": cstr(d.t_warehouse),
|
||||
"actual_qty": flt(d.transfer_qty),
|
||||
"incoming_rate": flt(d.incoming_rate)
|
||||
}))
|
||||
|
||||
self.make_sl_entries(sl_entries, self.doc.amended_from and 'Yes' or 'No')
|
||||
|
||||
def update_production_order(self, is_submit):
|
||||
if self.doc.production_order:
|
||||
@@ -632,26 +640,6 @@ class DocType(StockController):
|
||||
# to be assigned for finished item
|
||||
se_child.bom_no = bom_no
|
||||
|
||||
def add_to_values(self, d, wh, qty, is_cancelled):
|
||||
self.values.append({
|
||||
'item_code': d.item_code,
|
||||
'warehouse': wh,
|
||||
'posting_date': self.doc.posting_date,
|
||||
'posting_time': self.doc.posting_time,
|
||||
'voucher_type': 'Stock Entry',
|
||||
'voucher_no': self.doc.name,
|
||||
'voucher_detail_no': d.name,
|
||||
'actual_qty': qty,
|
||||
'incoming_rate': flt(d.incoming_rate, 2) or 0,
|
||||
'stock_uom': d.stock_uom,
|
||||
'company': self.doc.company,
|
||||
'is_cancelled': (is_cancelled ==1) and 'Yes' or 'No',
|
||||
'batch_no': cstr(d.batch_no).strip(),
|
||||
'serial_no': cstr(d.serial_no).strip(),
|
||||
"project": self.doc.project_name,
|
||||
"fiscal_year": self.doc.fiscal_year,
|
||||
})
|
||||
|
||||
def get_cust_values(self):
|
||||
"""fetches customer details"""
|
||||
if self.doc.delivery_note_no:
|
||||
|
||||
@@ -190,7 +190,7 @@ class DocType:
|
||||
self.update_serial_purchase_details(obj, d, a, is_submit, rejected=True)
|
||||
|
||||
|
||||
def update_stock(self, values, is_amended = 'No'):
|
||||
def update_stock(self, values, is_amended='No'):
|
||||
for v in values:
|
||||
sle_id, valid_serial_nos = '', ''
|
||||
# get serial nos
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-03-07 18:50:32",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-23 12:01:16",
|
||||
"modified": "2013-08-01 15:27:49",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -20,8 +20,7 @@
|
||||
"name": "__common__",
|
||||
"parent": "Warehouse",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"read_only": 0
|
||||
"parenttype": "DocType"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
@@ -29,9 +28,9 @@
|
||||
"parent": "Warehouse",
|
||||
"parentfield": "permissions",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1
|
||||
"report": 1,
|
||||
"submit": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
@@ -43,7 +42,8 @@
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Detail",
|
||||
"oldfieldtype": "Section Break",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -53,6 +53,7 @@
|
||||
"oldfieldname": "warehouse_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -65,14 +66,25 @@
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"description": "This account will be used for perpetual accounting for inventory e.g. Stock-in-Hand, Fixed Asset Account etc",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"description": "If set, data entry is only allowed for specified users. Else, entry is allowed for all users with requisite permissions.",
|
||||
@@ -81,7 +93,8 @@
|
||||
"fieldtype": "Table",
|
||||
"label": "Warehouse Users",
|
||||
"options": "Warehouse User",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"description": "For Reference Only.",
|
||||
@@ -89,7 +102,8 @@
|
||||
"fieldname": "warehouse_contact_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Contact Info",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -100,7 +114,8 @@
|
||||
"oldfieldname": "email_id",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0
|
||||
"print_hide": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -110,7 +125,8 @@
|
||||
"oldfieldname": "phone_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -120,14 +136,16 @@
|
||||
"oldfieldname": "mobile_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -136,7 +154,8 @@
|
||||
"label": "Address Line 1",
|
||||
"oldfieldname": "address_line_1",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -145,7 +164,8 @@
|
||||
"label": "Address Line 2",
|
||||
"oldfieldname": "address_line_2",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -156,6 +176,7 @@
|
||||
"oldfieldname": "city",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
@@ -166,7 +187,8 @@
|
||||
"oldfieldname": "state",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Suggest",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -175,7 +197,8 @@
|
||||
"label": "PIN",
|
||||
"oldfieldname": "pin",
|
||||
"oldfieldtype": "Int",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"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.",
|
||||
@@ -183,7 +206,8 @@
|
||||
"fieldname": "merge_warehouses_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Merge Warehouses",
|
||||
"permlevel": 2
|
||||
"permlevel": 2,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
@@ -191,22 +215,32 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Merge Into",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 2
|
||||
"permlevel": 2,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "merge",
|
||||
"fieldtype": "Button",
|
||||
"label": "Merge",
|
||||
"permlevel": 2
|
||||
"permlevel": 2,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"permlevel": 0,
|
||||
"role": "Material Master Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"permlevel": 0,
|
||||
"role": "System Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
@@ -214,20 +248,26 @@
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"doctype": "DocPerm",
|
||||
"role": "Material User",
|
||||
"submit": 0,
|
||||
"permlevel": 0,
|
||||
"role": "Material Manager",
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"doctype": "DocPerm",
|
||||
"role": "Sales User"
|
||||
"permlevel": 0,
|
||||
"role": "Material User",
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"doctype": "DocPerm",
|
||||
"role": "Purchase User"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"role": "Accounts User"
|
||||
"permlevel": 2,
|
||||
"role": "System Manager",
|
||||
"write": 1
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user