Sales performa Report
Public class PrintMgmtDocType_TEC_FreeTextInvoice_Handler
{
[SubscribesTo(classstr(PrintMgmtDocType), delegatestr(PrintMgmtDocType, getDefaultReportFormatDelegate))]
public static void getDefaultReportFormatDelegateHandler(PrintMgmtDocumentType _docType, EventHandlerResult _result)
{
switch(_docType)
{
case PrintMgmtDocumentType::SalesFreeTextInvoice:
_result.result(ssrsReportStr(TECDev3_FreeTextInvoice,ReportIN));
break;
case PrintMgmtDocumentType::SalesOrderInvoice:
_result.result(ssrsReportStr(TECGSTInvoiceReport_IN,ProformaReport));
break;
}
}
}
=====================================================================
[ExtensionOf(classStr(PrintMgmtReportFormatPopulator))]
final class PrintMgmtReportFormatPopulator_TEC_Extension
{
/// <summary>
/// Adds records to the <c>PrintMgmtReportFormat</c> table.
/// </summary>
protected void addDocuments()
{
#ISOCountryRegionCodes
#PrintMgmtSetup
next addDocuments();
this.addOther(PrintMgmtDocumentType::SalesOrderInvoice,
ssrsReportStr(TECGSTInvoiceReport_IN, ProformaReport), ssrsReportStr(TECGSTInvoiceReport_IN, ProformaReport), #isoIN);
}
}
====================================================================
[ExtensionOf(classStr(GSTInvoiceDPBase_IN))]
final class TECGSTInvoiceDPBase_INDPCls_Extension
{
public TECSalesProFormaTermsCondTmp tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
public TECTermsAndConditionTable tECTermsAndConditionTable;
/// <summary>
/// Gets data from the <c>TECSalesProFormaInvoiceTermsAndConditionTmp</c> table.
/// </summary>
/// <returns>
/// The data from the <c>TECSalesProFormaInvoiceTermsAndConditionTmp</c> table.
/// </returns>
[SRSReportDataSetAttribute(tableStr(TECSalesProFormaTermsCondTmp))]
public TECSalesProFormaTermsCondTmp getTECSalesOrderProFormaInvoiceTermsAndConditionTmp()
{
// this.setTransactionConnection(gstInvoiceTmp);
select tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
return tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
}
/// <summary>
/// Processes the report business logic.
/// </summary>
public void processReport()
{
this.setTransactionConnection(gstInvoiceTmp);
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.setConnection(this.parmUserConnection());
next processReport();
// this.setTransactionConnection(gstInvoiceTmp);
}
/// <summary>
/// Set the database transaction connection for a record from the connection associated with the report.
/// </summary>
/// <param name = "_reportRecord">
/// A record to set database transaction for.
/// </param>
final protected void setTransactionConnection(Common _reportRecord)
{
var connection = this.parmUserConnection();
if (connection)
{
_reportRecord.setConnection(connection);
}
}
public void createData()
{
// public TECSalesProFormaTermsCondTmp tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
const Name module = 'Accounts receivable';
next createData();
GSTInvoiceHeaderFooterTmp_IN GSTInvoiceHeaderFooterTmp_INVT;
//headerRecId;
//select GSTInvoiceHeaderFooterTmp_INVT where GSTInvoiceHeaderFooterTmp_INVT.RecId == headerRecId;
//if (GSTInvoiceHeaderFooterTmp_INVT)
//{
// delete_from tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
// while select * from tECTermsAndConditionTable
// order by tECTermsAndConditionTable.LineNo
// where tECTermsAndConditionTable.Module == module
// && tECTermsAndConditionTable.ReferenceId == GSTInvoiceHeaderFooterTmp_INVT.TECSalesId
// {
// // Assert and enable the system overwrite permission and metadata property.
// new OverwriteSystemfieldsPermission().assert();
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.overwriteSystemfields(true);
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.clear();
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.initValue();
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.LineNum = tECTermsAndConditionTable.LineNo;
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.TermDescription = tECTermsAndConditionTable.TermsDescription;
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.TermDetails = tECTermsAndConditionTable.TermsDetails;
// //tECSalesOrderProFormaInvoiceTermsAndConditionTmp.CreatedTransactionId = this.getGSTInvoiceHeaderFooterTmp().CreatedTransactionId;
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.(fieldNum(TECSalesProFormaTermsCondTmp,CreatedTransactionId)) =GSTInvoiceHeaderFooterTmp_INVT.CreatedTransactionId;
// // tECSalesOrderProFormaInvoiceTermsAndConditionTmp.(fieldNum(TECSalesProFormaTermsCondTmp, CreatedBy)) =GSTInvoiceHeaderFooterTmp_INVT.CreatedBy;
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.doInsert();
// // ttsbegin;
// // new OverwriteSystemfieldsPermission().assert();
// // tECSalesOrderProFormaInvoiceTermsAndConditionTmp.overwriteSystemfields(true);
// // tECSalesOrderProFormaInvoiceTermsAndConditionTmp.(fieldNum(TECSalesProFormaTermsCondTmp,CreatedTransactionId)) =this.getGSTInvoiceTmp().CreatedTransactionId;
// // tECSalesOrderProFormaInvoiceTermsAndConditionTmp.doUpdate();
// // Revert and disable the system overwrite permission and metadata property.
// tECSalesOrderProFormaInvoiceTermsAndConditionTmp.overwriteSystemfields(false);
// CodeAccessPermission::revertAssert();
// // ttscommit;
// }
//}
}
}
=================================================================
[ExtensionOf(classStr(TaxGSTSalesOrderInvoiceDP_IN))]
final class TECTaxGSTSalesOrderInvoiceDP_INCls_Extension
{
//public TECSalesProFormaTermsCondTmp tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
//public TECTermsAndConditionTable tECTermsAndConditionTable;
//public Name module = 'Accounts receivable';
protected void insertIntoGSTInvoiceHeaderFooterTmp()
{
//GSTInvoiceHeaderFooterTmp_IN gstInvoiceHeaderFooterTmp = this.gstInvoiceHeaderFooterTmp;
CompanyInfo companyInfo = CompanyInfo::find();
TaxInformationLegalEntity_IN taxInformationLegalEntity_IN;
TaxRegistrationNumbers_IN taxRegistrationNumbers_IN;
TaxInformation_IN taxInformation_IN;
TaxInformationCustTable_IN taxInformationCustTable_IN;
CustInvoiceJour custInvoiceJour = this.custInvoiceJour;
SalesTable salesTable = SalesTable::find(custInvoiceJour.SalesId);
SalesLine salesLine;
CustTable custTable = CustTable::find(salesTable.CustAccount);
HSNCodeTable_IN hSNCodeTable_IN;
ServiceAccountingCodeTable_IN serviceAccountingCodeTable_IN;
TaxTrans taxTrans;
InventTable inventTable;
Amount totalAmt;
ContactPerson contactPerson;
DirPersonName dirPersonName;
HcmWorker hcmWorker;
InventLocation inventLocation;
LogisticsPostalAddress compPostalAddress = companyInfo.postalAddress();
LogisticsElectronicAddress logisticsElectronicAddressCust;
LogisticsLocation logisticsLocationCust;
LogisticsPostalAddress postalAddress;
LogisticsEntityPostalAddressView postalAddressView;
gstInvoiceHeaderFooterTmp.TECCompName = companyInfo.Name;
gstInvoiceHeaderFooterTmp.TECCompAddr = compPostalAddress.Street+", "+compPostalAddress.City+", "+compPostalAddress.ZipCode+", "+LogisticsAddressState::find(compPostalAddress.CountryRegionId, compPostalAddress.State).Name+", "+compPostalAddress.CountryRegionId;
gstInvoiceHeaderFooterTmp.TECCompStateCode = LogisticsAddressState::find(compPostalAddress.CountryRegionId, compPostalAddress.State).StateCode_IN;
gstInvoiceHeaderFooterTmp.TECCompState = LogisticsAddressState::find(compPostalAddress.CountryRegionId, compPostalAddress.State).Name;
gstInvoiceHeaderFooterTmp.TECCompanyLogo = FormLetter::companyLogo();
select PANStatus, PANNumber from taxInformationLegalEntity_IN
where taxInformationLegalEntity_IN.LegalEntity == companyInfo.RecId;
if(taxInformationLegalEntity_IN.PANStatus == TaxPermanentAccountStatus_IN::Available)
{
gstInvoiceHeaderFooterTmp.TECCompPAN = taxInformationLegalEntity_IN.PANNumber;
}
select RegistrationNumber from taxRegistrationNumbers_IN
exists join taxInformation_IN
where taxInformation_IN.GSTIN == taxRegistrationNumbers_IN.RecId
&& taxInformation_IN.RegistrationLocation == compPostalAddress.Location
&& taxInformation_IN.IsPrimary == NoYes::Yes;
gstInvoiceHeaderFooterTmp.TECCompGSTIN = taxRegistrationNumbers_IN.RegistrationNumber;
gstInvoiceHeaderFooterTmp.TECSalesId = salesTable.SalesId;
gstInvoiceHeaderFooterTmp.TECPurchaseOrder = salesTable.PurchId;
gstInvoiceHeaderFooterTmp.TECCustomerPODate = salesTable.TECCustPODate;
gstInvoiceHeaderFooterTmp.TECDlvTerms = DlvTerm::find(salesTable.DlvTerm).Txt;
gstInvoiceHeaderFooterTmp.TECTANNo = "MUMS66925F";
gstInvoiceHeaderFooterTmp.TECPurchOrderFormNum = salesTable.PurchOrderFormNum;
gstInvoiceHeaderFooterTmp.TECPaymTerms = PaymTerm::find(salesTable.Payment).Description;
gstInvoiceHeaderFooterTmp.TECWarranty = salesTable.TECWarranty;
gstInvoiceHeaderFooterTmp.TECRemarks = salesTable.TECRemarks;
select hcmWorker
join inventLocation
where inventLocation.TECRefContactPerson == hcmWorker.RecId
&& inventLocation.InventLocationId == salesTable.InventLocationId
&& inventLocation.InventSiteId == salesTable.InventSiteId;
gstInvoiceHeaderFooterTmp.TECAccountingManagerName = hcmWorker.name();
gstInvoiceHeaderFooterTmp.TECAccountingManagerPhone = hcmWorker.phone();
gstInvoiceHeaderFooterTmp.TECAccountingManagerEmail = hcmWorker.email();
if(inventLocation)
{
select firstonly postalAddressView
where postalAddressView.Entity == inventLocation.RecId
&& postalAddressView.EntityType == LogisticsLocationEntityType::Warehouse
&& postalAddressView.isPrimary == NoYes::Yes;
gstInvoiceHeaderFooterTmp.TECWarehouseAddress = postalAddressView.Street+ ", "+postalAddressView.ZipCode +", "+LogisticsAddressState::find(postalAddressView.CountryRegionId, postalAddressView.State).Name+", "+ postalAddressView.CountryRegionId;
gstInvoiceHeaderFooterTmp.TECWarehouseStateId = LogisticsAddressState::find(postalAddressView.CountryRegionId, postalAddressView.State).StateCode_IN;
gstInvoiceHeaderFooterTmp.TECWarehouseStateName = LogisticsAddressState::find(postalAddressView.CountryRegionId, postalAddressView.State).Name;
select RegistrationNumber from taxRegistrationNumbers_IN
exists join taxInformation_IN
where taxInformation_IN.GSTIN == taxRegistrationNumbers_IN.RecId
&& taxInformation_IN.RegistrationLocation == inventLocation.logisticsPostalAddress().Location
&& taxInformation_IN.IsPrimary == NoYes::Yes;
gstInvoiceHeaderFooterTmp.TECWarehouseGSTIN = taxRegistrationNumbers_IN.RegistrationNumber;
gstInvoiceHeaderFooterTmp.TECWarehousePAN = gstInvoiceHeaderFooterTmp.TECCompPAN;
}
TransTaxInformation transTaxInformationBillTo = TransTaxInformationHelper::newHelper().findTransTaxInformationByRecord(salesLine::find(salesTable.SalesId));
LogisticsPostalAddress custLogisticsPostalAddress = LogisticsLocationEntity::location2PostalAddress(transTaxInformationBillTo.CustomerLocation, DateTimeUtil::getSystemDateTime(), true);
gstInvoiceHeaderFooterTmp.TECCustName = custTable.name();
gstInvoiceHeaderFooterTmp.TECCustAddress = strReplace(custLogisticsPostalAddress.Address,"\n",", ");
gstInvoiceHeaderFooterTmp.TECCustStateCode = LogisticsAddressState::find(custLogisticsPostalAddress.CountryRegionId, custLogisticsPostalAddress.State).StateCode_IN;
gstInvoiceHeaderFooterTmp.TECCustState = custLogisticsPostalAddress.State;
gstInvoiceHeaderFooterTmp.TECCustShipAddress = strReplace(salesLine::find(salesTable.SalesId).deliveryAddress().Address,"\n",", "); //strReplace(salesTable.deliveryAddress().Address,"\n",", ");
gstInvoiceHeaderFooterTmp.TECCustShipState = salesLine::find(salesTable.SalesId).deliveryAddress().State;//salesTable.deliveryAddress().State;
gstInvoiceHeaderFooterTmp.TECCustShipStateCode = LogisticsAddressState::find(salesLine::find(salesTable.SalesId).deliveryAddress().CountryRegionId,salesLine::find(salesTable.SalesId).deliveryAddress().State).StateCode_IN;//LogisticsAddressState::find(salesTable.deliveryAddress().CountryRegionId, salesTable.deliveryAddress().State).StateCode_IN;
select Description,Locator,Location from logisticsElectronicAddressCust
where logisticsElectronicAddressCust.Locator==salesTable.TECInvoicePhone || logisticsElectronicAddressCust.Locator==salesTable.TECInvoiceEmail
&& logisticsElectronicAddressCust.Type == LogisticsElectronicAddressMethodType::Phone
join logisticsLocationCust
where logisticsLocationCust.RecId == logisticsElectronicAddressCust.Location;
gstInvoiceHeaderFooterTmp.TECCustContactPersonName = logisticsElectronicAddressCust.Description;
gstInvoiceHeaderFooterTmp.TECCustContactPersonContact = salesTable.TECInvoicePhone;
select Description,Locator from logisticsElectronicAddressCust
where logisticsElectronicAddressCust.IsPrimary == NoYes::Yes
&& logisticsElectronicAddressCust.Type == LogisticsElectronicAddressMethodType::Email
join logisticsLocationCust
where logisticsLocationCust.RecId == logisticsElectronicAddressCust.Location
&& logisticsLocationCust.ParentLocation == postalAddress.Location;
gstInvoiceHeaderFooterTmp.TECCustContactPersonEmail = salesTable.TECInvoiceEmail;
select Description,Locator,Location from logisticsElectronicAddressCust
where logisticsElectronicAddressCust.Type == LogisticsElectronicAddressMethodType::Phone
join logisticsLocationCust
where logisticsLocationCust.RecId == logisticsElectronicAddressCust.Location;
gstInvoiceHeaderFooterTmp.TECCustShipContactPersonName = logisticsElectronicAddressCust.Description;
gstInvoiceHeaderFooterTmp.TECCustShipContact = salesTable.TECDeliveryPhone;
select Locator,Description from logisticsElectronicAddressCust
where logisticsElectronicAddressCust.Locator==salesTable.TECDeliveryEmail || logisticsElectronicAddressCust.Locator==salesTable.TECDeliveryPhone
&& logisticsElectronicAddressCust.Type == LogisticsElectronicAddressMethodType::Email
join logisticsLocationCust
where logisticsLocationCust.RecId == logisticsElectronicAddressCust.Location
&& logisticsLocationCust.ParentLocation == salesTable.deliveryAddress().Location;
if( !gstInvoiceHeaderFooterTmp.TECCustShipContactPersonName)
{
gstInvoiceHeaderFooterTmp.TECCustShipContactPersonName = logisticsElectronicAddressCust.Description;
}
gstInvoiceHeaderFooterTmp.TECCustShipContactPersonEmail = salesTable.TECDeliveryEmail;
select RegistrationNumber from taxRegistrationNumbers_IN
exists join taxInformation_IN
where taxInformation_IN.GSTIN == taxRegistrationNumbers_IN.RecId
&& taxInformation_IN.RegistrationLocation == salesLine::find(salesTable.SalesId).deliveryAddress().Location
&& taxInformation_IN.IsPrimary == NoYes::Yes;
select firstonly PANNumber, PANStatus from taxInformationCustTable_IN
where taxInformationCustTable_IN.CustTable == custTable.AccountNum;
gstInvoiceHeaderFooterTmp.TECCustShipGSTIN = taxRegistrationNumbers_IN.RegistrationNumber;
gstInvoiceHeaderFooterTmp.TECCustGSTIN = TaxRegistrationNumbers_IN::find(TaxInformation_IN::find(transTaxInformationBillTo.CustomerTaxInformation).GSTIN).RegistrationNumber;//taxRegistrationNumbers_IN.RegistrationNumber;
if(taxInformationCustTable_IN.PANStatus)
{
gstInvoiceHeaderFooterTmp.TECCustPAN = taxInformationCustTable_IN.PANNumber;
}
next insertIntoGSTInvoiceHeaderFooterTmp();
}
protected void insertIntoGSTInvoiceTmp(str _className)
{
CustInvoiceJour custInvoiceJour = this.custInvoiceJour;
CustInvoiceTrans custInvoiceTrans;
SalesTable salesTable = SalesTable::find(custInvoiceJour.SalesId);
SalesLine salesLine;
CustTable custTable = CustTable::find(salesTable.CustAccount);
InventTable inventTable ;
GSTInvoiceTmp_IN gstInvoiceTmp = this.gstInvoiceTmp;
TECSalesInvoiceBillingDetails tecSalesInvoiceBillingDetails;
TECProductComponents tECProductComponentsLoc;
Amount totalAmt, lastAmt;
AmountCur finalamount;
Amountcur roundOfvalue,RoundOfValueAmountInWords;
AmountCur finalAmountInwords;
AmountCur getRoundOfAmount;
int row;
if (tableNum(CustInvoiceTrans) == this.lineTableId)
{
custInvoiceTrans= CustInvoiceTrans::findRecId(this.lineRecId);
select firstonly ProductRefSerialNo from tecSalesInvoiceBillingDetails
where tecSalesInvoiceBillingDetails.RefRecId == custInvoiceTrans.RecId
&& tecSalesInvoiceBillingDetails.RefTableId == custInvoiceTrans.TableId;
if(tecSalesInvoiceBillingDetails.ProductRefSerialNo)
{
gstInvoiceTmp.TECProductRefSerialNo += " " + tecSalesInvoiceBillingDetails.ProductRefSerialNo + ",";
}
gstInvoiceTmp.TECSaleslinetext = custInvoiceTrans.salesLine().Name;
}
if (tableNum(CustInvoiceTrans) == this.lineTableId && classStr(ITaxDocumentLine) == _className)
{
custInvoiceTrans = CustInvoiceTrans::findRecId(this.lineRecId);
TEC_GSTHelper gstHelper = TEC_GSTHelper::constructCalculate(custInvoiceTrans.custInvoiceJour(),custInvoiceTrans);
gstInvoiceTmp.TECIGSTAmount = gstHelper.parmIGSTAmount();
gstInvoiceTmp.TECIGSTRate = gstHelper.parmIGSTRate() * 100;
gstInvoiceTmp.TECSGSTAmount = gstHelper.parmSGSTAmount();
gstInvoiceTmp.TECSGSTRate = gstHelper.parmSGSTRate() * 100;
gstInvoiceTmp.TECCGSTAmount = gstHelper.parmCGSTAmount();
gstInvoiceTmp.TECCGSTRate = gstHelper.parmCGSTRate() * 100;
gstInvoiceTmp.TECTotalAmount = gstInvoiceTmp.TaxableValue + gstInvoiceTmp.TECCGSTAmount + gstInvoiceTmp.TECSGSTAmount + gstInvoiceTmp.TECIGSTAmount;
gstInvoiceTmp.TECTotalGST = gstInvoiceTmp.TECCGSTAmount + gstInvoiceTmp.TECSGSTAmount + gstInvoiceTmp.TECIGSTAmount;
totalAmt += totalAmt + gstInvoiceTmp.TaxableValue + gstInvoiceTmp.TECCGSTAmount + gstInvoiceTmp.TECSGSTAmount + gstInvoiceTmp.TECIGSTAmount;
roundOfvalue = round(totalAmt,1);
getRoundOfAmount = totalAmt - roundOfvalue;
if(getRoundOfAmount > 0)
{
gstInvoiceTmp.TECRoundOffAmt = getRoundOfAmount;
}
else
{
gstInvoiceTmp.TECRoundOffAmt = -(getRoundOfAmount);
}
gstInvoiceTmp.TECFinalTotalAmount += roundOfvalue;//gstInvoiceTmp.TECTotalAmount;
// lastAmt += gstInvoiceTmp.TECFinalTotalAmount;
row = gstInvoiceTmp.RowNum;
}
gstInvoiceTmp.TECAmtInWords = Global::tecNumeralsToTxt_INDIA( gstInvoiceTmp.TECFinalTotalAmount);
next insertIntoGSTInvoiceTmp(_className);
if (tableNum(CustInvoiceTrans) == this.lineTableId && row)
{
inventTable = custInvoiceTrans.inventTable();
if(row == 1)
{
this.insertTermsAndCondition(salesTable,custInvoiceTrans, row);
}
this.insertComponents(inventTable,custInvoiceTrans, row);
GSTInvoiceTmp_IN gstInvoiceTmpUpdate = gstInvoiceTmp;
select sum(TECTotalAmount) from gstInvoiceTmpUpdate;
AmountCur finalTotalValue = gstInvoiceTmpUpdate.TECTotalAmount;
RoundOfValueAmountInWords = round(finalTotalValue,1);
update_recordset gstInvoiceTmpUpdate
setting TECAmtInWords =Global::tecNumeralsToTxt_INDIA(RoundOfValueAmountInWords);
}
}
private void insertComponents(InventTable _inventTable, custInvoiceTrans _custInvoiceTrans, int _rowNum)
{
TECProductComponents tECProductComponents;
// Qty qty = 1;
GSTInvoiceTmp_IN gstInvoiceTmp = this.gstInvoiceTmp;
RecId custInvoiceTransRecId = _custInvoiceTrans.RecId;
RecId custInvoiceJourRecId = _custInvoiceTrans.ParentRecId;
int value = 1;
insert_recordset gstInvoiceTmp(rowNum, JournalRecId, ItemId, TECRecordId, TECComponentName, TECComponentDescription, TECComponentQty, TECProductComponentAmount)
select _rowNum, custInvoiceJourRecId, ItemId, custInvoiceTransRecId, ComponentId, Description, Quantity , value from tECProductComponents
where tECProductComponents.ItemId == _inventTable.ItemId;
}
private void insertTermsAndCondition(SalesTable _salesTable, custInvoiceTrans _custInvoiceTrans,int _rowNum)
{
TECSalesProFormaTermsCondTmp tECSalesOrderProFormaInvoiceTermsAndConditionTmp;
TECTermsAndConditionTable tECTermsAndConditionTable;
const Name module = 'Accounts receivable';
GSTInvoiceTmp_IN gstInvoiceTmp = this.gstInvoiceTmp;
RecId custInvoiceTransRecId = _custInvoiceTrans.RecId;
RecId custInvoiceJourRecId = _custInvoiceTrans.ParentRecId;
insert_recordset gstInvoiceTmp(rowNum,JournalRecId,TECRecordId, TECTermDescription, TECTermDetails, TECLineNum)
select _rowNum,custInvoiceJourRecId,custInvoiceTransRecId, TermsDescription, TermsDetails, LineNo from tECTermsAndConditionTable
order by tECTermsAndConditionTable.LineNo
where tECTermsAndConditionTable.Module == module
&& tECTermsAndConditionTable.ReferenceId == _salesTable.SalesId;
}
}
========================================================================
Comments
Post a Comment