The MCost record do not is create with a new product.
https://sourceforge.net/tracker/?func=detail&atid=879332&aid=2496472&group_id=176962 Fixed the issue with 8078 New Functionality 1.- When you create a new client the Material, Resource, Burden , Overhead , Outside Processing Cost Elements are created, The reason this that ADempiere now only support to material for Standard Cost vut with Manufacturing Cost management is necessary implement the Resource, Burden , Overhead , Outside Processing Cost Elements 2.- When you create new product the MCost record is create for each cost element the same way that when you create a new client and the standard product is created 3.- The refactor and created the method for delete MCost record the same way that was created 4.- New method in MCostElemnt for manufacturing account 5.- Rename some method with best name getMaterialWithMethodCosting 6.- The MAcctSchema was fixed So the now ADempiere work the same work the same way to create product that when you create a new client.
This commit is contained in:
parent
79df183d68
commit
9ae07a2192
|
@ -18,7 +18,6 @@ package org.compiere.model;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@ -67,8 +66,6 @@ public class MAcctSchema extends X_C_AcctSchema
|
||||||
return retValue;
|
return retValue;
|
||||||
} // get
|
} // get
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get AccountSchema of Client
|
* Get AccountSchema of Client
|
||||||
* @param ctx context
|
* @param ctx context
|
||||||
|
@ -76,32 +73,43 @@ public class MAcctSchema extends X_C_AcctSchema
|
||||||
* @return Array of AcctSchema of Client
|
* @return Array of AcctSchema of Client
|
||||||
*/
|
*/
|
||||||
public static MAcctSchema[] getClientAcctSchema (Properties ctx, int AD_Client_ID)
|
public static MAcctSchema[] getClientAcctSchema (Properties ctx, int AD_Client_ID)
|
||||||
|
{
|
||||||
|
return getClientAcctSchema(ctx, AD_Client_ID, null);
|
||||||
|
} // getClientAcctSchema
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AccountSchema of Client
|
||||||
|
* @param ctx context
|
||||||
|
* @param AD_Client_ID client or 0 for all
|
||||||
|
* @param trxName optional trx
|
||||||
|
* @return Array of AcctSchema of Client
|
||||||
|
*/
|
||||||
|
public static MAcctSchema[] getClientAcctSchema (Properties ctx, int AD_Client_ID, String trxName)
|
||||||
{
|
{
|
||||||
// Check Cache
|
// Check Cache
|
||||||
if (s_schema.containsKey(AD_Client_ID))
|
Integer key = new Integer(AD_Client_ID);
|
||||||
return (MAcctSchema[])s_schema.get(AD_Client_ID);
|
if (s_schema.containsKey(key))
|
||||||
|
return (MAcctSchema[])s_schema.get(key);
|
||||||
|
|
||||||
// Create New
|
// Create New
|
||||||
ArrayList<MAcctSchema> list = new ArrayList<MAcctSchema>();
|
ArrayList<MAcctSchema> list = new ArrayList<MAcctSchema>();
|
||||||
MClientInfo info = MClientInfo.get(ctx, AD_Client_ID);
|
MClientInfo info = MClientInfo.get(ctx, AD_Client_ID, trxName);
|
||||||
MAcctSchema as = MAcctSchema.get (ctx, info.getC_AcctSchema1_ID());
|
MAcctSchema as = MAcctSchema.get (ctx, info.getC_AcctSchema1_ID(), trxName);
|
||||||
//if (as.get_ID() != 0 && trxName == null)
|
|
||||||
if (as.get_ID() != 0)
|
if (as.get_ID() != 0)
|
||||||
list.add(as);
|
list.add(as);
|
||||||
|
|
||||||
|
|
||||||
ArrayList<Object> params = new ArrayList<Object>();
|
ArrayList<Object> params = new ArrayList<Object>();
|
||||||
String whereClause = "EXISTS (SELECT 1 FROM C_AcctSchema_GL gl WHERE C_AcctSchema.C_AcctSchema_ID=gl.C_AcctSchema_ID)"
|
String whereClause = "IsActive=? "
|
||||||
+ " AND EXISTS (SELECT 1 FROM C_AcctSchema_Default d WHERE C_AcctSchema.C_AcctSchema_ID=d.C_AcctSchema_ID)";
|
+ " AND EXISTS (SELECT * FROM C_AcctSchema_GL gl WHERE C_AcctSchema.C_AcctSchema_ID=gl.C_AcctSchema_ID)"
|
||||||
|
+ " AND EXISTS (SELECT * FROM C_AcctSchema_Default d WHERE C_AcctSchema.C_AcctSchema_ID=d.C_AcctSchema_ID)";
|
||||||
|
params.add("Y");
|
||||||
if (AD_Client_ID != 0)
|
if (AD_Client_ID != 0)
|
||||||
{
|
{
|
||||||
whereClause += "AND AD_Client_ID=?";
|
whereClause += " AND AD_Client_ID=?";
|
||||||
params.add(AD_Client_ID);
|
params.add(AD_Client_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection <MAcctSchema> ass = new Query(ctx, MAcctSchema.Table_Name,whereClause, null)
|
List <MAcctSchema> ass = new Query(ctx, MAcctSchema.Table_Name,whereClause,trxName)
|
||||||
.setApplyAccessFilter(true)
|
|
||||||
.setParameters(params)
|
.setParameters(params)
|
||||||
.setOrderBy(MAcctSchema.COLUMNNAME_C_AcctSchema_ID)
|
.setOrderBy(MAcctSchema.COLUMNNAME_C_AcctSchema_ID)
|
||||||
.list();
|
.list();
|
||||||
|
@ -117,7 +125,7 @@ public class MAcctSchema extends X_C_AcctSchema
|
||||||
// Save
|
// Save
|
||||||
MAcctSchema[] retValue = new MAcctSchema [list.size()];
|
MAcctSchema[] retValue = new MAcctSchema [list.size()];
|
||||||
list.toArray(retValue);
|
list.toArray(retValue);
|
||||||
s_schema.put(AD_Client_ID, retValue);
|
s_schema.put(key, retValue);
|
||||||
return retValue;
|
return retValue;
|
||||||
} // getClientAcctSchema
|
} // getClientAcctSchema
|
||||||
|
|
||||||
|
|
|
@ -761,14 +761,82 @@ public class MCost extends X_M_Cost
|
||||||
* @param product product
|
* @param product product
|
||||||
**/
|
**/
|
||||||
protected static void create (MProduct product)
|
protected static void create (MProduct product)
|
||||||
|
{
|
||||||
|
s_log.config(product.getName());
|
||||||
|
|
||||||
|
// Cost Elements
|
||||||
|
Collection <MCostElement> ces = MCostElement.getCostElementsWithCostingMethods(product);
|
||||||
|
|
||||||
|
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(product.getCtx(),
|
||||||
|
product.getAD_Client_ID(), product.get_TrxName());
|
||||||
|
MOrg[] orgs = null;
|
||||||
|
|
||||||
|
int M_ASI_ID = 0; // No Attribute
|
||||||
|
for (MAcctSchema as : mass)
|
||||||
|
{
|
||||||
|
String cl = product.getCostingLevel(as);
|
||||||
|
// Create Std Costing
|
||||||
|
if (MAcctSchema.COSTINGLEVEL_Client.equals(cl))
|
||||||
|
{
|
||||||
|
for(MCostElement ce : ces)
|
||||||
|
{
|
||||||
|
MCost cost = MCost.get (product, M_ASI_ID,
|
||||||
|
as, 0, ce.getM_CostElement_ID());
|
||||||
|
if (cost.is_new())
|
||||||
|
{
|
||||||
|
if (cost.save())
|
||||||
|
s_log.config("Std.Cost for " + product.getName()
|
||||||
|
+ " - " + as.getName());
|
||||||
|
else
|
||||||
|
s_log.warning("Not created: Std.Cost for " + product.getName()
|
||||||
|
+ " - " + as.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (MAcctSchema.COSTINGLEVEL_Organization.equals(cl))
|
||||||
|
{
|
||||||
|
if (orgs == null)
|
||||||
|
orgs = MOrg.getOfClient(product);
|
||||||
|
for (MOrg o : orgs)
|
||||||
|
{
|
||||||
|
for(MCostElement ce : ces)
|
||||||
|
{
|
||||||
|
MCost cost = MCost.get (product, M_ASI_ID,
|
||||||
|
as, o.getAD_Org_ID(), ce.getM_CostElement_ID());
|
||||||
|
if (cost.is_new())
|
||||||
|
{
|
||||||
|
if (cost.save())
|
||||||
|
s_log.config("Std.Cost for " + product.getName()
|
||||||
|
+ " - " + o.getName()
|
||||||
|
+ " - " + as.getName());
|
||||||
|
else
|
||||||
|
s_log.warning("Not created: Std.Cost for " + product.getName()
|
||||||
|
+ " - " + o.getName()
|
||||||
|
+ " - " + as.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for all orgs
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_log.warning("Not created: Std.Cost for " + product.getName()
|
||||||
|
+ " - Costing Level on Batch/Lot");
|
||||||
|
}
|
||||||
|
} // accounting schema loop
|
||||||
|
} // create
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete standard Costing records for Product
|
||||||
|
* @param product product
|
||||||
|
**/
|
||||||
|
protected static void delete (MProduct product)
|
||||||
{
|
{
|
||||||
s_log.config(product.getName());
|
s_log.config(product.getName());
|
||||||
// Cost Elements
|
// Cost Elements
|
||||||
Collection <MCostElement> ces = MCostElement.getCostElementToCostingMethods(product);
|
Collection <MCostElement> ces = MCostElement.getCostElementsWithCostingMethods(product);
|
||||||
for(MCostElement ce : ces)
|
|
||||||
{
|
|
||||||
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(product.getCtx(),
|
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(product.getCtx(),
|
||||||
product.getAD_Client_ID());
|
product.getAD_Client_ID(), product.get_TrxName());
|
||||||
MOrg[] orgs = null;
|
MOrg[] orgs = null;
|
||||||
|
|
||||||
int M_ASI_ID = 0; // No Attribute
|
int M_ASI_ID = 0; // No Attribute
|
||||||
|
@ -778,16 +846,12 @@ public class MCost extends X_M_Cost
|
||||||
// Create Std Costing
|
// Create Std Costing
|
||||||
if (MAcctSchema.COSTINGLEVEL_Client.equals(cl))
|
if (MAcctSchema.COSTINGLEVEL_Client.equals(cl))
|
||||||
{
|
{
|
||||||
MCost cost = MCost.get (product, M_ASI_ID,
|
for(MCostElement ce : ces)
|
||||||
as, 0, ce.getM_CostElement_ID());
|
{
|
||||||
if (cost.is_new())
|
MCost cost = MCost.get (product, M_ASI_ID,
|
||||||
{
|
as, 0, ce.getM_CostElement_ID());
|
||||||
if (cost.save())
|
if(cost != null)
|
||||||
s_log.config("Std.Cost for " + product.getName()
|
cost.deleteEx(true);
|
||||||
+ " - " + as.getName());
|
|
||||||
else
|
|
||||||
s_log.warning("Not created: Std.Cost for " + product.getName()
|
|
||||||
+ " - " + as.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (MAcctSchema.COSTINGLEVEL_Organization.equals(cl))
|
else if (MAcctSchema.COSTINGLEVEL_Organization.equals(cl))
|
||||||
|
@ -796,18 +860,12 @@ public class MCost extends X_M_Cost
|
||||||
orgs = MOrg.getOfClient(product);
|
orgs = MOrg.getOfClient(product);
|
||||||
for (MOrg o : orgs)
|
for (MOrg o : orgs)
|
||||||
{
|
{
|
||||||
MCost cost = MCost.get (product, M_ASI_ID,
|
for(MCostElement ce : ces)
|
||||||
as, o.getAD_Org_ID(), ce.getM_CostElement_ID());
|
{
|
||||||
if (cost.is_new())
|
MCost cost = MCost.get (product, M_ASI_ID,
|
||||||
{
|
as, o.getAD_Org_ID(), ce.getM_CostElement_ID());
|
||||||
if (cost.save())
|
if(cost != null)
|
||||||
s_log.config("Std.Cost for " + product.getName()
|
cost.deleteEx(true);
|
||||||
+ " - " + o.getName()
|
|
||||||
+ " - " + as.getName());
|
|
||||||
else
|
|
||||||
s_log.warning("Not created: Std.Cost for " + product.getName()
|
|
||||||
+ " - " + o.getName()
|
|
||||||
+ " - " + as.getName());
|
|
||||||
}
|
}
|
||||||
} // for all orgs
|
} // for all orgs
|
||||||
}
|
}
|
||||||
|
@ -817,10 +875,8 @@ public class MCost extends X_M_Cost
|
||||||
+ " - Costing Level on Batch/Lot");
|
+ " - Costing Level on Batch/Lot");
|
||||||
}
|
}
|
||||||
} // accounting schema loop
|
} // accounting schema loop
|
||||||
}
|
|
||||||
} // create
|
} // create
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Calculate Average Invoice from Trx
|
* Calculate Average Invoice from Trx
|
||||||
* @param product product
|
* @param product product
|
||||||
|
@ -1603,7 +1659,9 @@ public class MCost extends X_M_Cost
|
||||||
*/
|
*/
|
||||||
protected boolean beforeSave (boolean newRecord)
|
protected boolean beforeSave (boolean newRecord)
|
||||||
{
|
{
|
||||||
MCostElement ce = getCostElement();
|
//The method getCostElement() not should be cached because is a transaction
|
||||||
|
//MCostElement ce = getCostElement();
|
||||||
|
MCostElement ce = (MCostElement)getM_CostElement();
|
||||||
// Check if data entry makes sense
|
// Check if data entry makes sense
|
||||||
if (m_manual)
|
if (m_manual)
|
||||||
{
|
{
|
||||||
|
|
|
@ -781,7 +781,7 @@ public class MCostDetail extends X_M_CostDetail
|
||||||
// Create Material Cost elements
|
// Create Material Cost elements
|
||||||
if (getM_CostElement_ID() == 0)
|
if (getM_CostElement_ID() == 0)
|
||||||
{
|
{
|
||||||
MCostElement[] ces = MCostElement.getMaterialCostingMethods(this);
|
MCostElement[] ces = MCostElement.getMaterialWithCostingMethods(this);
|
||||||
for (int i = 0; i < ces.length; i++)
|
for (int i = 0; i < ces.length; i++)
|
||||||
{
|
{
|
||||||
MCostElement ce = ces[i];
|
MCostElement ce = ces[i];
|
||||||
|
@ -1130,7 +1130,7 @@ public class MCostDetail extends X_M_CostDetail
|
||||||
// Create Material Cost elements
|
// Create Material Cost elements
|
||||||
if (getM_CostElement_ID() == 0)
|
if (getM_CostElement_ID() == 0)
|
||||||
{
|
{
|
||||||
MCostElement[] ces = MCostElement.getMaterialCostingMethods(this);
|
MCostElement[] ces = MCostElement.getMaterialWithCostingMethods(this);
|
||||||
for (int i = 0; i < ces.length; i++)
|
for (int i = 0; i < ces.length; i++)
|
||||||
{
|
{
|
||||||
MCostElement ce = ces[i];
|
MCostElement ce = ces[i];
|
||||||
|
|
|
@ -191,11 +191,12 @@ public class MCostElement extends X_M_CostElement
|
||||||
* @param po parent
|
* @param po parent
|
||||||
* @return cost element array
|
* @return cost element array
|
||||||
*/
|
*/
|
||||||
public static Collection<MCostElement> getCostElementToCostingMethods (PO po)
|
public static Collection<MCostElement> getCostElementsWithCostingMethods (PO po)
|
||||||
{
|
{
|
||||||
final String whereClause = "CostingMethod IS NOT NULL";
|
final String whereClause = "CostingMethod IS NOT NULL";
|
||||||
return new Query(po.getCtx(),MCostElement.Table_Name,whereClause,po.get_TrxName())
|
return new Query(po.getCtx(),MCostElement.Table_Name,whereClause,po.get_TrxName())
|
||||||
.setOnlyActiveRecords(true)
|
.setOnlyActiveRecords(true)
|
||||||
|
.setClient_ID()
|
||||||
.list();
|
.list();
|
||||||
} // getCostElementCostingMethod
|
} // getCostElementCostingMethod
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ public class MCostElement extends X_M_CostElement
|
||||||
* @param po parent
|
* @param po parent
|
||||||
* @return cost element array
|
* @return cost element array
|
||||||
*/
|
*/
|
||||||
public static MCostElement[] getMaterialCostingMethods (PO po)
|
public static MCostElement[] getMaterialWithCostingMethods (PO po)
|
||||||
{
|
{
|
||||||
ArrayList<MCostElement> list = new ArrayList<MCostElement>();
|
ArrayList<MCostElement> list = new ArrayList<MCostElement>();
|
||||||
String sql = "SELECT * FROM M_CostElement "
|
String sql = "SELECT * FROM M_CostElement "
|
||||||
|
@ -384,12 +385,18 @@ public class MCostElement extends X_M_CostElement
|
||||||
protected boolean beforeSave (boolean newRecord)
|
protected boolean beforeSave (boolean newRecord)
|
||||||
{
|
{
|
||||||
// Check Unique Costing Method
|
// Check Unique Costing Method
|
||||||
if (COSTELEMENTTYPE_Material.equals(getCostElementType())
|
if (
|
||||||
|
( COSTELEMENTTYPE_Material.equals(getCostElementType())
|
||||||
|
|| COSTELEMENTTYPE_Resource.equals(getCostElementType())
|
||||||
|
|| COSTELEMENTTYPE_BurdenMOverhead.equals(getCostElementType())
|
||||||
|
|| COSTELEMENTTYPE_Overhead.equals(getCostElementType())
|
||||||
|
|| COSTELEMENTTYPE_OutsideProcessing.equals(getCostElementType())
|
||||||
|
)
|
||||||
&& (newRecord || is_ValueChanged("CostingMethod")))
|
&& (newRecord || is_ValueChanged("CostingMethod")))
|
||||||
{
|
{
|
||||||
String sql = "SELECT COALESCE(MAX(M_CostElement_ID),0) FROM M_CostElement "
|
String sql = "SELECT COALESCE(MAX(M_CostElement_ID),0) FROM M_CostElement "
|
||||||
+ "WHERE AD_Client_ID=? AND CostingMethod=?";
|
+ "WHERE AD_Client_ID=? AND CostingMethod=? AND CostElementType=?";
|
||||||
int id = DB.getSQLValue(get_TrxName(), sql, getAD_Client_ID(), getCostingMethod());
|
int id = DB.getSQLValue(get_TrxName(), sql, getAD_Client_ID(), getCostingMethod() , getCostElementType());
|
||||||
if (id > 0 && id != get_ID())
|
if (id > 0 && id != get_ID())
|
||||||
{
|
{
|
||||||
log.saveError("AlreadyExists", Msg.getElement(getCtx(), "CostingMethod"));
|
log.saveError("AlreadyExists", Msg.getElement(getCtx(), "CostingMethod"));
|
||||||
|
|
|
@ -622,7 +622,7 @@ public class MProduct extends X_M_Product
|
||||||
"p.M_Product_Category_ID=" + getM_Product_Category_ID());
|
"p.M_Product_Category_ID=" + getM_Product_Category_ID());
|
||||||
insert_Tree(X_AD_Tree.TREETYPE_Product);
|
insert_Tree(X_AD_Tree.TREETYPE_Product);
|
||||||
//
|
//
|
||||||
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
|
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID(), get_TrxName());
|
||||||
for (int i = 0; i < mass.length; i++)
|
for (int i = 0; i < mass.length; i++)
|
||||||
{
|
{
|
||||||
// Old
|
// Old
|
||||||
|
@ -673,12 +673,14 @@ public class MProduct extends X_M_Product
|
||||||
for (int i = 0; i < costings.length; i++)
|
for (int i = 0; i < costings.length; i++)
|
||||||
costings[i].delete(true, get_TrxName());
|
costings[i].delete(true, get_TrxName());
|
||||||
|
|
||||||
|
MCost.delete(this);
|
||||||
|
|
||||||
// [ 1674225 ] Delete Product: Costing deletion error
|
// [ 1674225 ] Delete Product: Costing deletion error
|
||||||
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(),getAD_Client_ID());
|
/*MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(),getAD_Client_ID(), get_TrxName());
|
||||||
for(int i=0; i<mass.length; i++)
|
for(int i=0; i<mass.length; i++)
|
||||||
{
|
{
|
||||||
// Get Cost Elements
|
// Get Cost Elements
|
||||||
MCostElement[] ces = MCostElement.getMaterialCostingMethods(this);
|
MCostElement[] ces = MCostElement.getMaterialWithCostingMethods(this);
|
||||||
MCostElement ce = null;
|
MCostElement ce = null;
|
||||||
for(int j=0; j<ces.length; j++)
|
for(int j=0; j<ces.length; j++)
|
||||||
{
|
{
|
||||||
|
@ -694,7 +696,7 @@ public class MProduct extends X_M_Product
|
||||||
|
|
||||||
MCost mcost = MCost.get(this, 0, mass[i], 0, ce.getM_CostElement_ID());
|
MCost mcost = MCost.get(this, 0, mass[i], 0, ce.getM_CostElement_ID());
|
||||||
mcost.delete(true, get_TrxName());
|
mcost.delete(true, get_TrxName());
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//
|
//
|
||||||
return delete_Accounting("M_Product_Acct");
|
return delete_Accounting("M_Product_Acct");
|
||||||
|
@ -750,7 +752,7 @@ public class MProduct extends X_M_Product
|
||||||
public boolean isASIMandatory(boolean isSOTrx) {
|
public boolean isASIMandatory(boolean isSOTrx) {
|
||||||
//
|
//
|
||||||
// If CostingLevel is BatchLot ASI is always mandatory - check all client acct schemas
|
// If CostingLevel is BatchLot ASI is always mandatory - check all client acct schemas
|
||||||
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
|
MAcctSchema[] mass = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID(), get_TrxName());
|
||||||
for (MAcctSchema as : mass)
|
for (MAcctSchema as : mass)
|
||||||
{
|
{
|
||||||
String cl = getCostingLevel(as);
|
String cl = getCostingLevel(as);
|
||||||
|
|
|
@ -606,7 +606,7 @@ public class POSProductManager extends ProductManager
|
||||||
{
|
{
|
||||||
MClient client = new MClient(ctx, Env.getAD_Client_ID(ctx), null);
|
MClient client = new MClient(ctx, Env.getAD_Client_ID(ctx), null);
|
||||||
|
|
||||||
MCostElement costElements[] = MCostElement.getMaterialCostingMethods(client);
|
MCostElement costElements[] = MCostElement.getMaterialWithCostingMethods(client);
|
||||||
|
|
||||||
for(int i = 0; i < costElements.length; i++)
|
for(int i = 0; i < costElements.length; i++)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue