Verifone X990 not respone by C# .NET

I tried to write code in C# and I connected with RS232 to send HEX I needed EDC Verifone X990 to respond but now my EDC Verifone X990 has not responded to anything.

in the project now I have 3 files.

ConnectSerialPort.cs

using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.Ports;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography;
using System.Text;


public class ConnectSerialPort
{
    public string PortName;
    public SerialPort serialPort;
    public List<string> availablePorts = new List<string>();
    public ConnectSerialPort()
    {
        GetAvailablePorts();
    }

    public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        Console.WriteLine("Can connect or response IN");
        string invoice = string.Empty;
        string invoiceHex = "";
        Calculator _calculator = new Calculator();
        if (serialPort.BytesToRead > 0)
        {
            Console.WriteLine("Can connect or response IN1");
        }

    }
    private PackData _packData = new PackData();

    public void WriteToSerialPort(string port)
    {
        try
        {
            StringBuilder xmlData = new StringBuilder();
            xmlData.AppendFormat("<xml>" +
                "<trade_type>" + "CARD" + "</trade_type>" +
                "<amount>" + 100.25 + "</amount>" +
                "<pos_ref_no>" + "IV20181001000011" + "</pos_ref_no>" +
                "<transaction_type>" + "SALE" + "</transaction_type>" +
                //"<service_type>" + "SHOWQR" + "</service_type>" +
                "</xml>");

            byte[] buffer = Encoding.UTF8.GetBytes("02004136303030303030303030313032303030301C343000123030303030303030303033321C37340001321C034C");
            Console.WriteLine("send data byte array : " + buffer.Length);
            Console.WriteLine(port);
            StartPayment(3, 100, "000000");
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
    public void StartPayment(int mode, decimal price, string reference)
    {
        try
        {
            PrintData dataPack = new PrintData();
            if ((int)mode == 3)
            {
                var printData = new PrintData()
                {
                    TranCode = "70",
                    Price = price,
                    Optional = "0",
                    Mode = "03",
                    Invoice = "0",
                    Reference = reference
                };
                dataPack = printData;
            }
            else if ((int)mode == 4)
            {
                var printData = new PrintData()
                {
                    TranCode = "20",
                    Price = price,
                    Optional = "0",
                    Invoice = "0",
                    Reference = reference
                };
                dataPack = printData;
            }
            else
            {
                Console.WriteLine("Wrong Payment choice");
            }

            var fomat = _packData.PackDataMessageStructure(dataPack);
            foreach (var f in fomat) {
                Console.Write(f);
            }

            
            serialPort.Write(fomat, 0, fomat.Length);
            bgReader.RunWorkerAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Payment Error : " + ex.Message);
        }
    }
    void GetAvailablePorts()
    {
        availablePorts.Clear();
        string[] ports = SerialPort.GetPortNames();
        availablePorts.AddRange(ports);
    }

    public void SetSelectedPort(int index)
    {
        Console.WriteLine("Set Port Index : " + availablePorts[index]);
        if (availablePorts.Count > 0)
        {
            PortName = availablePorts[index];
            Console.WriteLine("Set Port : " + PortName);
            OnPortDropdownValueChanged();
        }
    }
    BackgroundWorker bgReader;

    void OnPortDropdownValueChanged()
    {
        serialPort = new SerialPort(PortName);
        serialPort.BaudRate = 9600;
        serialPort.Parity = Parity.None;
        serialPort.DataBits = 8;
        //serialPort.Handshake = Handshake.None; 
        serialPort.StopBits = StopBits.One;
        serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
        if (serialPort.IsOpen)
        {
            serialPort.Close();
        }
        try
        {
            serialPort.Open();
            bgReader = new BackgroundWorker
            {
                WorkerReportsProgress = false,
                WorkerSupportsCancellation = true
            };

            bgReader.DoWork += new DoWorkEventHandler(BgReader_OnDoWork);
            Console.WriteLine($"Serial port {serialPort.PortName} opened successfully. + {serialPort.IsOpen}");
        }
        catch (System.Exception ex)
        {
            Console.WriteLine($"Error opening serial port: {ex.Message}");
        }
    }
    void BgReader_OnDoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = (BackgroundWorker)sender;
        Console.WriteLine("Other1");

        while (!worker.CancellationPending)
        {
            try
            {
                if (serialPort.BytesToRead > 0)
                {
                    Console.WriteLine("OtherTest");
                }
            }
            catch (Exception ex)
            {
                //Logger.Error("Error in processing: " + ex.Message);
            }
        }
    }
    public void DisConnectPort()
    {
        if (serialPort != null && serialPort.IsOpen)
        {
            serialPort.Close();
            Console.WriteLine("Serial port closed.");
        }
    }
    public static string ConvertToHex(string cardRangeSelector, decimal amount, string merchantNumber, string ref1, string ref2)
    {
        StringBuilder hexBuilder = new StringBuilder();

        // Convert REQD Field (Card Range Selector) to Hex
        hexBuilder.Append(Convert.ToByte(cardRangeSelector[0]).ToString("X2"));

        // Convert OPTL Field (Amount) to Hex
        int amountInCents = (int)(amount * 100);
        hexBuilder.Append(amountInCents.ToString("X12"));

        // Convert OPTL Field (Merchant Number) to Hex
        hexBuilder.Append(Convert.ToByte(merchantNumber[0]).ToString("X2"));

        // Convert OPTL Field (Generic Data/Ref#1) to Hex
        hexBuilder.Append(Encoding.ASCII.GetBytes(ref1).Length.ToString("X2"));
        hexBuilder.Append(Encoding.ASCII.GetBytes(ref1).ToHex());

        // Convert OPTL Field (Generic Data/Ref#2) to Hex
        hexBuilder.Append(Encoding.ASCII.GetBytes(ref2).Length.ToString("X2"));
        hexBuilder.Append(Encoding.ASCII.GetBytes(ref2).ToHex());

        return hexBuilder.ToString();
    }
    public string calculateSignature(IEnumerable<KeyValuePair<string, string>> requestPayloadValues, string secretKey, string currentDate)
    {
        int size = 0;
        string hash = string.Empty;
        UTF8Encoding encoding = new UTF8Encoding();
        System.Text.StringBuilder PlainDataToHash = new System.Text.StringBuilder();
        var res = requestPayloadValues.GetEnumerator();

        while (res.MoveNext())
        {
            switch (res.Current.Key)
            {
                case "IPN_PID[]":
                    size = res.Current.Value.Length;

                    PlainDataToHash.Append(size);
                    PlainDataToHash.Append(res.Current.Value);
                    break;
                case "IPN_PNAME[]":
                    size = res.Current.Value.Length;

                    PlainDataToHash.Append(size);
                    PlainDataToHash.Append(res.Current.Value);
                    break;
                case "IPN_DATE":
                    size = res.Current.Value.Length;

                    PlainDataToHash.Append(size);
                    PlainDataToHash.Append(res.Current.Value);
                    break;
            }
        }
        size = currentDate.Length;
        PlainDataToHash.Append(size);
        PlainDataToHash.Append(currentDate);

        Console.WriteLine(PlainDataToHash);

        string pass = secretKey;
        byte[] passBytes = encoding.GetBytes(pass);

        // sha256; for sha3-256, replace HMACSHA256 with HMACSHA3_256
        HMACSHA256 hmacSha = new HMACSHA256(passBytes);
        string HashData = PlainDataToHash.ToString();

        byte[] baseStringForHashBytes = encoding.GetBytes(HashData);
        byte[] hashBytes = hmacSha.ComputeHash(baseStringForHashBytes);

        hash = ByteToString(hashBytes);

        return hash;
    }
    public static string ByteToString(byte[] buff)
    {
        string sbinary = "";
        for (int i = 0; i < buff.Length; i++)
        {
            sbinary += buff[i].ToString("x2"); // hex format
        }
        return (sbinary);
    }

    public string generateTag(IEnumerable<KeyValuePair<string, string>> requestPayloadValues, string secretKey)
    {
        var now = DateTime.Now.ToString("yyyyMMddHHmmss");
        var responseHash = calculateSignature(requestPayloadValues, secretKey, now);

        // sha256; for sha3-256, replace algo="sha256" with algo="sha3-256"
        return $"<sig algo="sha256" date="{now}">{responseHash}</sig>";
    }
}
public static class ExtensionMethods
{
    // Extension method to convert string to Hex
    public static string ToHex(this byte[] bytes)
    {
        StringBuilder hexBuilder = new StringBuilder();
        foreach (byte b in bytes)
        {
            hexBuilder.Append(b.ToString("X2"));
        }
        return hexBuilder.ToString();
    }
}

PackDataBase.cs

using System.Text;

public class Calculator
{
    public byte CalculateLRC(List<byte> bytes)
    {
        byte lrc = 0;
        for (int i = 0; i < bytes.Count; i++)
        {
            lrc ^= bytes[i];
        }
        lrc.ToString("X2");
        return lrc;
    }
    public string[] ASCIItoHex(string value)
    {
        byte[] inputByte = Encoding.UTF8.GetBytes(value);
        var result = inputByte.Select(item => string.Format("{0:x2}", item)).ToArray();
        return result;
    }
    public string[] GetLLLLValue(int value)
    {
        //LLLL field data calculator
        int llll = value;
        string[] result = new string[2];
        string llll1 = "00";
        string llll2 = "41";
        if (llll > 0 && llll <= 255)
        {
            llll2 = llll.ToString();
            result[0] = llll1;
            result[1] = llll2;
        }
        else
        {
            //input more than 256 or input = 0 or input -1
            throw new Exception("input more than 256 byte");
        }
        //------------------------------------------------------------------------------------
        return result;
    }
    public int ParseBCD(byte[] input)
    {
        var val = 0;
        string str = "";
        foreach (var b in input)
        {
            str += b.ToString("X2");
        }
        int.TryParse(str, out val);
        return val;
    }
    public byte[] StringToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                         .ToArray();
    }
    public string HexadecimalToASCII(string hex)
    {
        string ascii = "";

        for (int i = 0; i < hex.Length; i += 2)
        {
            ascii += (char)HexadecimalToDecimal(hex.Substring(i, 2));
        }
        return ascii;
    }
    public int HexadecimalToDecimal(string hex)
    {
        hex = hex.ToUpper();

        int hexLength = hex.Length;
        double dec = 0;

        for (int i = 0; i < hexLength; ++i)
        {
            byte b = (byte)hex[i];

            if (b >= 48 && b <= 57)
                b -= 48;
            else if (b >= 65 && b <= 70)
                b -= 55;

            dec += b * Math.Pow(16, ((hexLength - i) - 1));
        }

        return (int)dec;
    }
}
public class FieldData
{
    public Calculator _calculator = new Calculator();
    public List<byte> FieldDataMessageForSaleQR(decimal price, string mode, string optional, string referenceTagNo)
    {
        int llll = 0;
        string fs = "1c";
        //Main input
        //------------------------------------------------------------------------------------
        string[] FTAT = _calculator.ASCIItoHex("40");
        int priceInt = decimal.ToInt32(price * 100);
        llll = priceInt.ToString().Length;
        var llllp = _calculator.GetLLLLValue(12);
        var priceC = _calculator.ASCIItoHex(priceInt.ToString());
        var pc = 12 - llll;
        //------------------------------------------------------------------------------------
        var FTPM = _calculator.ASCIItoHex("A1");
        if (mode == "01")
        {
            Console.WriteLine("Alipay Payment");
        }
        else if (mode == "02")
        {
            Console.WriteLine("Wechat Payment");
        }
        else if (mode == "03")
        {
            Console.WriteLine("QR Code Payment");
        }
        else if (mode == "04")
        {
            Console.WriteLine("QR Credit Payment");
        }
        else if (mode == "30")
        {
            Console.WriteLine("Dolfin Payment");
        }
        else if (mode == "99")
        {
            Console.WriteLine("Other Payment");
        }
        llll = mode.Length;
        var llllc = _calculator.GetLLLLValue(llll);
        var modeHex = _calculator.ASCIItoHex(mode);
        //Optional input
        //------------------------------------------------------------------------------------
        string[] FTR1;
        string r1;
        string[] llllr1 = new string[2];
        FTR1 = _calculator.ASCIItoHex("R1");
        llll = referenceTagNo.Length;
        llllr1 = _calculator.GetLLLLValue(20);
        var r11 = _calculator.ASCIItoHex(referenceTagNo);
        var FTR1c = 20 - llll;
        if (optional == "1")
        {
        }
        //------------------------------------------------------------------------------------         
        //Pack Message Data
        List<string> input = new List<string>();
        if (optional == "0")
        {
            input.AddRange(FTAT);
            input.Add(llllp[0]);
            input.Add(llllp[1]);
            for (int i = 0; i < pc; i++)
            {
                if (i < pc)
                {
                    input.Add("30");
                }
            }
            input.AddRange(priceC);
            input.Add(fs);
            input.AddRange(FTPM);
            input.Add(llllc[0]);
            input.Add(llllc[1]);
            input.AddRange(modeHex);
            input.Add(fs);
            input.AddRange(FTR1);
            input.Add(llllr1[0]);
            input.Add(llllr1[1]);
            for (int i = 0; i < FTR1c; i++)
            {
                if (i < pc)
                {
                    input.Add("30");
                }
            }
            input.AddRange(r11);
            input.Add(fs);
        }
        else if (optional == "1")
        {
        }
        //------------------------------------------------------------------------------------
        List<byte> fef = input.Select(s => Convert.ToByte(s, 16)).ToList();
        return fef;
    }
    public List<byte> FieldDataMessageForSaleStandard(decimal price, string optional)
    {
        int llll = 0;
        string fs = "1c";
        //Main input
        //------------------------------------------------------------------------------------
        string[] ftat = _calculator.ASCIItoHex("40");
        int priceInt = decimal.ToInt32(price * 100);
        llll = priceInt.ToString().Length;
        var llllp = _calculator.GetLLLLValue(12);
        var priceC = _calculator.ASCIItoHex(priceInt.ToString());
        var pc = 12 - llll;
        //Optional input
        //------------------------------------------------------------------------------------
        string[] FTR1;
        string r1;
        string[] FTR2;
        string r2;
        string[] llllr1 = new string[2];
        string[] llllr2 = new string[2];
        if (optional == "1")
        {
        }
        //------------------------------------------------------------------------------------         
        //Pack Message Data
        List<string> input = new List<string>();
        if (optional == "0")
        {
            input.AddRange(ftat);
            input.Add(llllp[0]);
            input.Add(llllp[1]);
            for (int i = 0; i < pc; i++)
            {
                if (i < pc)
                {
                    input.Add("30");
                }
            }
            input.AddRange(priceC);
            input.Add(fs);
        }
        /*else if (optional == "1")
        {
            //input = $"{FTAT} {LLLLP[0]} {LLLLP[1]} {priceC} {FS} {FTPM} {LLLLC[0]} {LLLLC[1]} {mode} {FS} {FTR1} {LLLLR1[0]} {LLLLR1[1]} {r1} {FS} {FTR1} {LLLLR2[0]} {LLLLR2[1]} {r2} {FS}";
        }*/
        //------------------------------------------------------------------------------------
        List<byte> fef = input.Select(s => Convert.ToByte(s, 16)).ToList();
        return fef;
    }
    public List<byte> FieldDataMessageForVoid(string invoice)
    {

        int llll = 0;
        string fs = "1c";
        //Main input
        //------------------------------------------------------------------------------------
        string[] ftat = _calculator.ASCIItoHex("65");
        llll = invoice.Length;
        var llllp = _calculator.GetLLLLValue(6);
        var invoiceNoC = _calculator.ASCIItoHex(invoice);
        var pc = 6 - llll;
        //Optional input
        //------------------------------------------------------------------------------------
        string[] llllr1 = new string[2];
        string[] llllr2 = new string[2];
        //------------------------------------------------------------------------------------         
        //Pack Message Data
        List<string> input = new List<string>();
        input.AddRange(ftat);
        input.Add(llllp[0]);
        input.Add(llllp[1]);
        input.AddRange(invoiceNoC);
        input.Add(fs);
        //------------------------------------------------------------------------------------
        List<byte> fef = input.Select(s => Convert.ToByte(s, 16)).ToList();
        return fef;
    }
}
public class GetMessage
{
    public MessageInfo GetMessages(byte[] input)
    {
        Calculator _calculator = new Calculator();
        if (input[0] != 0x02) return null;
        var len = _calculator.ParseBCD(new byte[] { input[1], input[2] });
        // Check tail.
        if (input.Length == len + 5 && input[input.Length - 2] == 0x03)
        {
            var transportBytes = new byte[10];
            Array.Copy(input, 3, transportBytes, 0, 10);
            var tranDat = System.Text.Encoding.ASCII.GetString(transportBytes);
            TransportHeader tran = new TransportHeader
            {
                Type = tranDat.Substring(0, 2),
                Destination = tranDat.Substring(2, 4),
                Source = tranDat.Substring(6, 4),
            };
            var presentBytes = new byte[8];
            Array.Copy(input, 13, presentBytes, 0, 8);
            var presDat = System.Text.Encoding.ASCII.GetString(presentBytes);
            PresentationHeader pres = new PresentationHeader
            {
                FormatVer = presDat.Substring(0, 1),
                Type = presDat.Substring(1, 1),
                TransactionCode = presDat.Substring(2, 2),
                ResponseCode = presDat.Substring(4, 2),
                MoreMessage = presDat.Substring(6, 1) == "1",
                LastChar = presentBytes[7].ToString("X2")
            };
            // read all datas.
            List<Element> element = new List<Element>();
            int index = 21;
            while (index < 3 + len)
            {
                var typeCode = System.Text.Encoding.ASCII.GetString(new byte[] { input[index], input[index + 1] });
                var elementLength = _calculator.ParseBCD(new byte[] { input[index + 2], input[index + 3] });
                var elementBytes = new byte[elementLength];
                Array.Copy(input, index + 4, elementBytes, 0, elementLength);
                var elementData = System.Text.Encoding.ASCII.GetString(elementBytes);
                element.Add(new Element { Type = typeCode, Length = elementLength, Data = elementData });
                index += elementLength + 5;
            }

            return new MessageInfo
            {
                Transport = tran,
                Presentation = pres,
                Size = len,
                Datas = element
            };
        }
        return null;
    }
}
public class PackData
{
    public byte[] PackDataMessageStructure(PrintData printData)
    {
        FieldData fieldData = new FieldData();
        Calculator calculator = new Calculator();
        MessageStruture message = new MessageStruture();
        byte lrc;
        List<string> rri = new List<string>() { "30", "31", "32" };
        string tc = printData.TranCode;
        var tcc = calculator.ASCIItoHex(tc.ToString());
        List<string> mi = new List<string>() { "30", "31" };
        List<byte> fdm;
        if (tc == "70")
        {
            fdm = fieldData.FieldDataMessageForSaleQR(printData.Price, printData.Mode, printData.Optional, printData.Reference);
        }
        else if (tc == "26")
        {
            fdm = fieldData.FieldDataMessageForVoid(printData.Invoice);
        }
        else if (tc == "20")
        {
            fdm = fieldData.FieldDataMessageForSaleStandard(printData.Price, printData.Optional);
        }
        else if (tc == "4")
        {
            fdm = null;
        }
        else
        {
            throw new Exception("Not Match Payment");
        }
        List<byte> fomat;
        string input;
        if (tc == "70" || tc == "26" || tc == "20")
        {
            input = $"{message.THT1} {message.THT2} {message.TD1} {message.TD2} {message.TD3} {message.TD4} {message.TS1} {message.TS2} {message.TS3} {message.TS4} {message.FV} {rri[0]} {tcc[0]} {tcc[1]} {message.RC1} {message.RC2} {mi[0]}";
            fomat = input.Split().Select(s => Convert.ToByte(s, 16)).ToList();
            fomat.Add(message.FS);
            fomat.AddRange(fdm);
            string llllc = fomat.Count.ToString();
            int decValue = Convert.ToInt32(llllc, 16);
            var llll = calculator.GetLLLLValue(decValue);
            fomat.Insert(0, Convert.ToByte(llll[1]));
            fomat.Insert(0, Convert.ToByte(llll[0]));
            fomat.Add(Convert.ToByte(message.ETX));
            lrc = calculator.CalculateLRC(fomat);
            fomat.Add(lrc);
            fomat.Insert(0, Convert.ToByte(message.STX));
            return fomat.ToArray();
        }
        else if (tc == "4")
        {
            var example = new byte[] { 0x02, 0x00, 0x18, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x44, 0x30, 0x30, 0x30, 0x30, 0x1c, 0x03, 0x44 };
            return example;
        }
        else
        {
            return null;
        }
    }
}
public class MessageInfo
{
    public int Size { get; set; }
    public TransportHeader Transport { get; set; }
    public PresentationHeader Presentation { get; set; }
    public List<Element> Datas { get; set; }
}

public class TransportHeader
{
    public string Type { get; set; }
    public string Destination { get; set; }
    public string Source { get; set; }
}

public class PresentationHeader
{
    public string FormatVer { get; set; }
    public string Type { get; set; }
    public string TransactionCode { get; set; }
    public string ResponseCode { get; set; }
    public bool MoreMessage { get; set; }
    public string LastChar { get; set; }
}

public class Element
{
    public string Type { get; set; }
    public int Length { get; set; }
    public string Data { get; set; }
}
public class MessageStruture
{
    // front
    public string STX = "02";
    // back
    public string ETX = "03";
    // Transport Header(TH)
    public string THT1 = "36";
    public string THT2 = "30";
    public string TD1 = "30";
    public string TD2 = "30";
    public string TD3 = "30";
    public string TD4 = "30";
    public string TS1 = "30";
    public string TS2 = "30";
    public string TS3 = "30";
    public string TS4 = "30"; //total 10 byte
                              // Presentation Header(PH)
    public string FV = "31";
    public byte FS = 0x1c;
    public string RC1 = "30";
    public string RC2 = "30";
}

public class PrintData
{
    public string TranCode { get; set; }
    public decimal Price { get; set; }
    public string Optional { get; set; }
    public string Mode { get; set; }
    public string Invoice { get; set; }
    public string Reference { get; set; }
}
public class TransactionResult
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public string Invoice { get; set; }
}

Program.cs

using System.Text;

string cardRangeSelector = "V";
decimal amount = 100.50m;
string merchantNumber = "1";
string ref1 = "Ref1";
string ref2 = "Ref2";

string hexData = ConnectSerialPort.ConvertToHex(cardRangeSelector, amount, merchantNumber, ref1, ref2);

Console.WriteLine(hexData);
var connect = new ConnectSerialPort();


Console.WriteLine($"Read Port");
for (int i = 0; i < connect.availablePorts.Count; i++)
    Console.WriteLine($"{i} : {connect.availablePorts[i]}");


Console.Write("Select a port (enter the corresponding number): ");
string userInput = Console.ReadLine();

if (int.TryParse(userInput, out int selectedPortIndex) && selectedPortIndex >= 0 && selectedPortIndex < connect.availablePorts.Count)
{
    string selectedPort = connect.availablePorts[selectedPortIndex];
    Console.WriteLine($"You selected port: {selectedPort}");

    connect.SetSelectedPort(selectedPortIndex);
    while (true)
    {
        string inputconfirm = Console.ReadLine();
        Console.Write("Select a Mode (enter the corresponding number): " + inputconfirm);
        connect.WriteToSerialPort(hexData);
    }
}
else
{
    Console.WriteLine("Invalid input. Please enter a valid number corresponding to the port.");
}

I tried to Open the Serial Port and send the HEX request messages and I expected EDC Verifone X990 to respond to the response messages but EDC didn’t respond to anything.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật