Course C-2

[견적 처리] 수정 및 출력물 개발

목표

  • 테이블의 기본 키에 자동 채번 로직을 적용하고, XtraReport와 Spreadsheet의 Mail Merge 기능을 이용해 출력물 및 SubForm 개발을 실습합니다.

  • 학습 인정 시간: 5 시간

1. 기본 키 시스템 채번

1.1) 관리번호 채번정보 등록

  • [GSTBrowser → 시스템 → 관리번호 채번정보] 메뉴를 실행합니다.

  • 신규 버튼을 클릭하여 아래 사진과 같이 채번 정보를 입력하고 저장합니다.

1.2) 저장용 프로시저 수정 (작업 타입: 신규)

  • (A) : 채번용 프로시저 (P_GetNumber_new)를 사용하여 OUTPUT 타입 파라미터로 견적번호(quonum)를 받아옵니다.

  • (B) : 견적 상세 테이블(SA051T_xxx)을 처리할 때 테이블 변수(@tb_SA050T_xxx)의 IDENTITY 특성 필드인 "idx"를 견적 순번(quoseq)로 사용합니다.

  • ※ 채번 프로시저의 적용으로 [C-1]에서 진행했던 견적 번호(quonum)의 중복 키 체크 로직은 더 이상 필요하지 않습니다.

1.3) 저장용 프로시저 수정 (작업 타입: 수정)

  • 견적 기본 테이블(SA050T_xxx)의 UPDATE와 견적 상세 테이블(SA051T_xxx)의 DELETE, UPDATE는 B-1에서 진행한 "4.4) 작업 타입: 수정 (@p_work_type = 'U')" 패턴과 동일합니다.

  • C-1에서 사용자로부터 입력 받았던 견적 순번(quoseq)을 중복되지 않도록 프로시저에서 처리합니다.

  • 견적 상세 테이블에 견적 번호(quonum)의 마지막 순번을 임시 변수(@v_max_seq)에 보관합니다.

  • (A) : 처리하려는 테이블 변수의 신규 행(row_status='N')에 대해서만 ROW_NUMBER 함수를 사용해 마지막 순번(@v_max_seq)에 행 번호(row_num)를 더하여 견적 순번(quoseq)을 업데이트 합니다.

  • ※ 마찬가지로 자동 순번 생성을 적용함에 따라 견적 순번(quoseq)의 중복 키 체크 로직은 더 이상 필요하지 않습니다.

2. 프로그램 수정

  • 더 이상 사용자로부터 견적 번호를 입력 받지 않기 때문에 [기본정보] 영역의 견적번호 TextEditEx 컨트롤의 AllowBlank 속성을 true로 변경하고, 항상 읽기 전용 상태를 유지합니다.

  • 그리고 저장 버튼을 클릭했을 때 저장용 프로시저를 실행하는 메서드에 작업 타입을 전달하는 방법을 아래 코드처럼 수정합니다.

public override void ClickSaveButton()
{
    // 견적 번호가 빈 값이면 신규 입력 상태
    if (Func_P_DEV003_xxx_S(string.IsNullOrEmpty(txtQuonum1.Text) ? "N" : "U"))
    {
        ClickRetrieveButton();
    }
}

  • 마찬가지로 [상세정보] 영역의 견적 순번 GridColumnEx에 ColumnOperation 속성의 값을 None으로 변경하고 ReadOnly 상태로 만들어 준 다음 위치를 가장 뒤로 옮겨줍니다.

3. 출력물 (XtraReport)

3.1) 출력물용 쿼리 작성

  • 조회용 프로시저(P_DEV003_xxx_Q)를 열고, 출력물에 대한 작업 타입(@p_work_type='print')에 대한 쿼리를 작성합니다.

  • 두 개의 결과를 반환하는데, 첫 번째 결과로 Report의 Header와 Footer에 바인딩 목적이며 두 번째 결과는 Detail에 바인딩하는데 사용됩니다.

  • (A): 출력물에 값이 없는 빈 행(Row)을 표현하기 위한 용도로 테이블 변수를 정의합니다.

  • (B): 테이블 변수를 이용해 견적 상세 정보를 조회합니다.

  • ※ [빈 행으로 채우기 (출력물)] 예시 쿼리 참고

3.2) 프로젝트에 XtraReport.cs 파일 추가

  • [VisualStudio→프로젝트→새 항목] Report Wizard (.NET Framework)를 선택하고 "Quotation.cs" 파일을 추가, "Empty Report" 선택 후 Finish 버튼을 클릭합니다.

3.3) XtraReport 디자인

  • 디자인 탭에서 마우스 우클릭하여 ReportHeader, PageHeader, ReportFooter를 추가합니다.

  • 도구 상자에서 XRLabel, XRTable을 적절히 사용하여 견적서 출력물을 디자인합니다.

[견적서 예시 화면]

3.4) XtraReport 데이터 바인딩 코드 작성

3.5) 폼에서 출력물 실행 기능 구현

  • OnLoad 메서드에서 미리보기 버튼을 활성화합니다.

  • 조회용 프로시저 호출 메서드에 출력물 작업 타입(workType="print")에 대한 결과를 받아오기 위해 메서드에 out 파라미터 한정자를 사용합니다.

  • 그리고 미리보기 버튼 클릭 메서드 (ClickPreviewButton)에 기능을 구현합니다.

확장 메서드 "ShowPreviewDialog"를 사용하기 위해선 네임스페이스 "DevExpress.XtraReports.UI"를 using 지시문으로 등록해야 합니다.

// OnLoad
...
EnabledPreviewButton = true;
...
private bool Func_P_DEV003_xxx_Q(string workType, out DataSet results)
{
    results = null;
    
    if (!ValidateControls(grpTop))
        return false;

    string quonum = string.Empty;
    string frdt = string.Empty;
    string todt = string.Empty;
    string custnm = string.Empty;
    string person = string.Empty;

    if (workType.Equals("list"))
    {
        quonum = txtQuonum.Text;
        frdt = ymdFromDate.yyyymmdd;
        todt = ymdToDate.yyyymmdd;
        custnm = txtCustnm.Text;
        person = cboPerson.EditValue?.ToString() ?? string.Empty;
    }
    else if (workType.Equals("detail") || workType.Equals("print"))
    {
        quonum = gvwList.GetValue("quonum")?.ToString() ?? string.Empty;
    }

    try
    {
        P_DEV003_xxx_Q procInfo = new P_DEV003_xxx_Q();

        procInfo.AddParamData(
            workType,
            quonum,
            frdt,
            todt,
            custnm,
            person);

        ResultSet result = ExecuteProcedure(procInfo);

				if (workType.Equals("list"))
				{
            SetData(grdList, result?[0]);
				}
        else if (workType.Equals("detail"))
        {
            SetData(grdDetail, result?[0]);
        }
        else if (workType.Equals("print"))
        {
            results = result.ResultDataSet;
        }

        return result?.IsSuccess ?? false;
    }
    catch (Exception ex)
    {
        ShowErrorMessageBox(ex);
        return false;
    }
}
// ClickRetrieveButton
...
if (Func_P_DEV003_xxx_Q("list", out _))
...

// FocusedRowChanged
...
Func_P_DEV003_xxx_Q("detail", out _);
...
using DevExpress.XtraReports.UI;

...

public override void ClickPreviewButton()
{
    if (gvwList.FocusedRowHandle < 0)
    {
        ShowMessageBox(GetFormMessage("PROJECTBASE_012", "선택된 자료가 없습니다."));
        return;
    }

    if (Func_P_DEV003_xxx_Q("print", out DataSet results))
    {
        Quotation report = new Quotation(results);
        report.ShowPreviewDialog();
    }
}

3.6) 출력물 확인

  • 프로그램을 실행하여 출력물이 정상적으로 보여지는지 확인합니다.

4. 출력물 (Spreadsheet Mail Merge)

4.1) 메뉴 등록 및 배포

  • 엑셀 메일 머지 설정을 위해 먼저 메뉴 정보를 등록합니다.

  • 이후 [어셈블리 배포], [메뉴 배포]를 순서대로 진행합니다.

4.2) 메일 머지 기준 정보 등록

  • [GPM→엑셀 메일머지]에서 등록 여부를 '전체'로 선택하고 조회합니다.

  • 위에서 등록한 "견적처리_xxx" 메뉴를 선택하고 신규 버튼을 클릭합니다.

  • '문서타입' 항목에 "견적서"를 선택하고, '타입ID'에 "DEV003_xxx_1"을 입력합니다.

  • [Query] 영역에 "<Set Parameter>" 텍스트 위에 DECLARE @p_quonum varchar(20) = '' 를 입력하고, [ 3.1) 출력물용 쿼리 작성 ]에서 작성했던 쿼리를 "<Set Parameter>" 아래에 붙여넣습니다.

  • 이후 결과 테이블 별칭에 대괄호('[ ]')를 입력합니다.

  • "Apply" 버튼을 클릭하고, [항목타입별 상세정보] 영역에 '테이블 및 전달변수', '관계 정보' 탭의 내용을 아래 사진을 참고하여 입력합니다.

  • 설정이 끝나면 우측 [결과 미리보기] 영역에 "돋보기" 버튼을 클릭하여 다음 사진과 같이 결과가 정상적으로 나오는지 확인하고 "저장" 버튼을 클릭합니다.

4.3) 엑셀 출력물 등록

  • [GSTBrowser → 시스템 → 엑셀 출력물 관리] 메뉴를 실행합니다.

  • 메뉴를 조회하고 "견적처리_xxx" 메뉴를 선택하여 신규 버튼을 클릭하여 '문서타입' 항목에 "견적서"를 선택하고, '문서명' 항목에 "견적서"를 입력합니다.

  • Spreadsheet 영역에 아래 사진을 참고하여 디자인 합니다.

  • 완성된 Spreadsheet 양식에 셀 영역을 선택하고, 'Template Ranges' 도구 메뉴를 이용하여 Mail Merge 영역을 지정합니다. (※ 아래 사진을 참고하여 순서대로 지정)

  • 영역을 지정하고나면 값을 표현할 셀을 선택하여 [필드 리스트] 영역의 항목을 더블 클릭해서 필드를 세팅하고 저장 버튼을 클릭합니다.

4.4) 작업 결과 미리보기

  • [GPM→엑셀 메일머지]에 등록한 메일 머지 기준 정보에서 다음 사진과 같이 스칼라 변수(@p_quonum)에 유효한 견적번호로 값을 초기화 시켜두고 저장합니다. (※ 확인 작업이 끝나면 반드시 빈 값으로 다시 초기화 해두도록 합니다.)

  • [GSTBrowser→엑셀 출력물 관리]에서 데이터를 다시 조회하고, Mail Merge Preview 버튼을 클릭하면 데이터가 바인딩된 Spreadsheet를 팝업에서 확인할 수 있고, 해당 팝업에서 Print Preview 버튼을 클릭하여 실제 인쇄될 화면을 확인하여 셀의 크기나, 최대 행 개수 등을 조정합니다.

4.5) 폼에서 출력물 실행 기능 구현

  • XtraReport 방식의 출력물 코드는 주석으로 처리해두고, 엑셀 출력물을 실행하는 코드를 작성합니다.

  • ※ ExcelMailMerge 클래스에 자세한 내용은 [기능 문서]를 확인바랍니다.

public override void ClickPreviewButton()
{
    if (gvwList.FocusedRowHandle < 0)
    {
        ShowMessageBox(GetFormMessage("PROJECTBASE_012", "선택된 자료가 없습니다."));
        return;
    }

    //// XtraReport
    //if (Func_P_DEV003_xxx_Q("print", out DataSet results))
    //{
    //    Quotation report = new Quotation(results);
    //    report.ShowPreviewDialog();
    //}

    // 엑셀 출력물
    string quonum = gvwList.GetFocusedRowCellValue("quonum")?.ToString() ?? string.Empty;

    var paramValues  = new Dictionary<string, object>();
    paramValues.Add("@p_quonum", quonum);
    
    ExcelMailMerge.Preview("DEV003_xxx_1", paramValues);
}

4.6) 출력물 확인

  • 프로그램을 실행하여 출력물이 정상적으로 보여지는지 확인합니다.

5. SubForm 적용

※ 앞에서 개발한 두 가지 출력물을 SubForm을 이용하여 사용자가 선택한 출력물이 보여지도록 하는 기능을 구현합니다. ([SubForm 기능 문서] 참고)

5.1) 서브 폼 화면 개발

  • 새 Form을 등록하여 화면을 디자인하고, [GPM Tools→용어정보]에서 용어 정보를 매핑합니다.

5.2) 서브 폼 기능 구현

  • 외부에서 선택한 출력물 타입을 참조하기 위해 새로운 enum 타입과 Property를 정의하고, 각 이벤트에 대한 코드를 작성합니다.

using GST.Platform.Client.BaseMenu;
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace GST.GWERP.EDU
{
    public partial class DEV003_xxx_Sub1 : BaseMenu
    {
        internal PrintType PrintType { get; private set; }

        public DEV003_xxx_Sub1()
        {
            InitializeComponent();

            StartPosition = FormStartPosition.CenterParent;
            MaximumSize = MinimumSize = Size;
            MaximizeBox = MinimizeBox = false;

            btnOk.Click += OnClick;
            btnCancel.Click += OnClick;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // 출력 타입 항목을 열거형으로 초기화
            radPrintType.Properties.AddEnum(typeof(PrintType));
            radPrintType.EditValue = PrintType.XtraReport;
        }

        private void OnClick(object sender, EventArgs e)
        {
            if (sender.Equals(btnOk))
            {
                DialogResult = DialogResult.OK;
            }
            this.Close();
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            Enum.TryParse(radPrintType.EditValue?.ToString(), out PrintType printType);
            PrintType = printType;
        }
    }

    internal enum PrintType
    {
        XtraReport,
        [Description("Spreadsheet Mail Merge")]
        SpreadsheetMailMerge
    }
}

5.3) 메뉴 폼에 서브 폼 기능 구현

  • CreateSubForm 메서드를 통해 서브 폼을 띄우고, 확인 버튼을 클릭했을때만 선택한 PrintType을 참조하여 출력물이 실행되도록 합니다.

public override void ClickPreviewButton()
{
    if (gvwList.FocusedRowHandle < 0)
    {
        ShowMessageBox(GetFormMessage("PROJECTBASE_012", "선택된 자료가 없습니다."));
        return;
    }

    // 출력물 타입 선택 팝업
    var popup = CreateSubForm<DEV003_xxx_Sub1>();

    if (popup.ShowDialog(this) != DialogResult.OK)
        return;

    // XtraReport
    if (popup.PrintType == PrintType.XtraReport)
    { 
        if (Func_P_DEV003_xxx_Q("print", out DataSet results))
        {
            Quotation report = new Quotation(results);
            report.ShowPreviewDialog();
        }
    }
    // 엑셀 출력물
    else if (popup.PrintType == PrintType.SpreadsheetMailMerge)
    {
        string quonum = gvwList.GetFocusedRowCellValue("quonum")?.ToString() ?? string.Empty;

        var paramValues = new Dictionary<string, object>();
        paramValues.Add("@p_quonum", quonum);

        ExcelMailMerge.Preview("DEV003_xxx_1", paramValues);
    }
}

6. 체크 리스트

  • 신규 저장 시 시스템 채번에 의해 견적 번호가 정상적으로 저장되는지 확인합니다.

  • 출력물 타입 선택 옵션 팝업을 통해 선택된 출력물이 각각 정상적으로 표현되는지 확인합니다.

Last updated

Was this helpful?